新聞中心
前言
在前面整理了一篇關(guān)于JVM故障診斷和處理工具,考慮到大部分的Java程序員都使用的時(shí)IntelliJ Idea,本篇就使用工具來(lái)實(shí)戰(zhàn)演練對(duì)IntelliJ Idea運(yùn)行速度調(diào)優(yōu)

成都創(chuàng)新互聯(lián)公司是一家集網(wǎng)站建設(shè),文縣企業(yè)網(wǎng)站建設(shè),文縣品牌網(wǎng)站建設(shè),網(wǎng)站定制,文縣網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷(xiāo),網(wǎng)絡(luò)優(yōu)化,文縣網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專(zhuān)業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶(hù)成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
調(diào)優(yōu)前的運(yùn)行狀態(tài)
原始配置內(nèi)容
要查詢(xún)idea原始配置文件的路徑可以在VisualVM中的概述中查看
原始配置內(nèi)容:
- -XX:ReservedCodeCacheSize=240m
- -XX:+UseCompressedOops
- -Dfile.encoding=UTF-8
- -XX:SoftRefLRUPolicyMSPerMB=50
- -ea
- -Dsun.io.useCanonCaches=false
- -Djava.net.preferIPv4Stack=true
- -Djdk.http.auth.tunneling.disabledSchemes=""
- -XX:+HeapDumpOnOutOfMemoryError
- -XX:-OmitStackTraceInFastThrow
- -XX:ErrorFile=$USER_HOME/java_error_in_idea_%p.log
- -XX:HeapDumpPath=$USER_HOME/java_error_in_idea.hprof
- -Xmx512m
打印啟動(dòng)時(shí)間插件開(kāi)發(fā)
需要直觀地看到優(yōu)化前和優(yōu)化后啟動(dòng)時(shí)間的變化,所以需要簡(jiǎn)單做一個(gè)Idea的插件開(kāi)發(fā),關(guān)于Idea插件開(kāi)發(fā)的流程建議參考我以前的文章《IDEA插件:多線程文件下載插件開(kāi)發(fā) 》
JVM的啟動(dòng)時(shí)間到所有組件初始化完成后的時(shí)間就看做是IDEA的啟動(dòng)時(shí)間,代碼如下
- public class MyApplicationInitializedListener implements ApplicationInitializedListener {
- @Override
- public void componentsInitialized() {
- RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
- long startTime = bean.getStartTime();
- long costTime = System.currentTimeMillis() - startTime;
- Messages.showMessageDialog("毫秒:" + costTime, "啟動(dòng)耗時(shí)", Messages.getInformationIcon());
- }
- }
plugin.xml中添加如下代碼:
- implementation="cn.silently9527.MyApplicationInitializedListener"/>
優(yōu)化前的啟動(dòng)信息與時(shí)間消耗
根據(jù)VisualGC和IDEA啟動(dòng)插件收集到的信息:
- IDEA啟動(dòng)耗時(shí) 15s
- 總共垃圾收集22次,耗時(shí)1.2s,其中新生代GC 17次,耗時(shí)324ms; 老年代GC 5次,耗時(shí)953ms
- 加載類(lèi)27526個(gè),耗時(shí) 21s
按照這個(gè)數(shù)據(jù)來(lái)看也算是正常,15s 其實(shí)也在接受范圍內(nèi),由于本文主要演示性能調(diào)優(yōu),所以需要測(cè)試能否再快一些
開(kāi)始嘗試優(yōu)化
調(diào)整內(nèi)存來(lái)控制垃圾回收頻率
圖上我們可以看出,啟動(dòng)參數(shù)指定的512m的內(nèi)存被分配到新生代的只有169m,由于IDEA是我們開(kāi)發(fā)常用的工具,平時(shí)的編譯過(guò)程也需要足夠的內(nèi)存,所以我們需要先把總的內(nèi)存擴(kuò)大,這里我設(shè)置最大的內(nèi)存-Xmx1024m,為了讓JVM在GC期間不需要再浪費(fèi)時(shí)間再動(dòng)態(tài)計(jì)算擴(kuò)容大小,同時(shí)也設(shè)置了-Xms1024m;
在啟動(dòng)的過(guò)程中Eden共發(fā)生了17次GC,為了減少新生代gc次數(shù),我把新生代的內(nèi)存大小設(shè)置成-Xmn256m;
重新啟動(dòng)之后查看VisualGC,新生代gc次數(shù)從 17次 降低到了 7次,耗時(shí)從 324ms 降低到了 152ms。
在調(diào)整內(nèi)存前發(fā)生了5次Full GC,調(diào)整內(nèi)存后的依然還是有4次Full GC,但是從兩張圖我們可以看出,老年代的空間還有很多剩余,是不應(yīng)該發(fā)生Full GC的;考慮是否是代碼中有地方手動(dòng)調(diào)用System.gc()觸發(fā)了Full GC,所以添加了參數(shù)-XX:+DisableExplicitGC,再次重新啟動(dòng)IDEA,結(jié)果很失望,依然還有4次Full GC;
再次仔細(xì)觀察優(yōu)化前的圖,注意看 Last Cause: Metadata GC Threshold , 最后一次gc是應(yīng)該Metaspace區(qū)域內(nèi)存不夠發(fā)生的GC,為了驗(yàn)證我們的猜想,打印出GC日志來(lái)看看。在idea.vmoptions中添加打印日志相關(guān)的參數(shù):
- -XX:+PrintGCDetails
- -XX:+PrintGCDateStamps
- -Xloggc:../gc.log
JVM的GC日志的主要參數(shù)包括如下幾個(gè):
-XX:+PrintGC 輸出GC日志
-XX:+PrintGCDetails 輸出GC的詳細(xì)日志
-XX:+PrintGCTimeStamps 輸出GC的時(shí)間戳(以基準(zhǔn)時(shí)間的形式)
-XX:+PrintGCDateStamps 輸出GC的時(shí)間戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
-XX:+PrintHeapAtGC 在進(jìn)行GC的前后打印出堆的信息
-Xloggc:../logs/gc.log 日志文件的輸出路徑
重新啟動(dòng)idea,查看gc.log
其中PSYoungGen:表示新生代使用的ParallelScavenge垃圾收集器,31416K->0K(181248K)表示 gc前已使用的內(nèi)存大小 -> gc后已使用內(nèi)存大?。ㄔ搮^(qū)域的總內(nèi)存大?。?/p>
從日志中我們看出每次Full GC都是因?yàn)镸etadata GC Threshold,而Metaspace每次gc回收的內(nèi)存幾乎沒(méi)有,僅僅是擴(kuò)大了該區(qū)域的容量;找到了原因那就好辦了,添加如下的參數(shù)調(diào)整Metaspace的大?。?code>
- -XX:MetaspaceSize=256m
再次重啟Idea之后,發(fā)現(xiàn)Full GC沒(méi)有了,心情很爽
測(cè)試打開(kāi)大項(xiàng)目點(diǎn)擊編譯代碼,發(fā)現(xiàn)自己的idea卡死了,查看VisualGC之后發(fā)現(xiàn)堆內(nèi)存都還有空閑,只有Metaspace被全部占滿了,所以是自己給的最大空間設(shè)置太小,所以直接去掉了-XX:MaxMetaspaceSize=256m
選擇垃圾收集器
從剛才的gc日志中,我們可以發(fā)現(xiàn)默認(rèn)使用的是ParallelScavenge + Parallel Old垃圾收集器,這個(gè)組合注重的是吞吐量,這里我們嘗試換一個(gè)注重低延時(shí)的垃圾收集器試一試
- ParNew + CMS 在idea.vmoptions中添加如下配置:
- -XX:+UseConcMarkSweepGC
- -XX:+UseParNewGC
重啟IDEA之后查看VisualGC
很尷尬,同樣發(fā)生了6次gc,ParallelScavenge + Parallel Old的組合耗時(shí)197ms,而ParNew + CMS的組合耗時(shí)379ms;雖然是這個(gè)結(jié)果,但是我們需要考慮當(dāng)前只發(fā)生了MinorGC,如果發(fā)生FullGC了結(jié)果又會(huì)如何了,大家可以自己測(cè)試一下
- G1 我們?cè)贀Q一個(gè)最新的G1垃圾回收器試試,在idea.vmoptions中添加如下配置:
- -XX:+UseG1GC
這個(gè)結(jié)果好像也還是要慢一點(diǎn)點(diǎn),自己多次測(cè)試過(guò)這兩個(gè)垃圾回收器,雖然每次結(jié)果都不一樣,相差不遠(yuǎn),所以垃圾回收器可以自己選擇,這里我們選擇的是G1
類(lèi)加載時(shí)間優(yōu)化
根據(jù)之前的分析,idea啟動(dòng)加載類(lèi)27526個(gè),耗時(shí) 21s,這個(gè)我們有辦法能優(yōu)化一下嗎?因?yàn)閕dea是常用的開(kāi)發(fā)工具,經(jīng)常很多人的使用,我們可以認(rèn)為它的代碼是安全的,是否符合當(dāng)前虛擬機(jī)的要求,不會(huì)危害虛擬機(jī)的安全,所以我們使用參數(shù)-Xverify:none來(lái)禁用字節(jié)碼的驗(yàn)證過(guò)程
重啟IDEA
耗時(shí)下降到了11s,效果還是比較明顯的
總結(jié)
做完了所有優(yōu)化之后,經(jīng)過(guò)多次重啟測(cè)試,平均的啟動(dòng)時(shí)間下降到了11s,為了安慰我本次操作沒(méi)有白辛苦,搞一張11s以下的圖
網(wǎng)站名稱(chēng):JVM性能調(diào)優(yōu)實(shí)戰(zhàn):讓你的IntelliJIdea縱享絲滑
標(biāo)題鏈接:http://www.dlmjj.cn/article/dpijioe.html


咨詢(xún)
建站咨詢(xún)
