JVM性能調優實戰:讓你的IntelliJ Idea縱享絲滑

本文已被Github倉庫收錄 https://github.com/silently9527/JavaCorejava

微信公衆號:貝塔學Javagit

前言

在前面整理了一篇關於JVM故障診斷和處理工具,考慮到大部分的Java程序員都使用的時IntelliJ Idea,本篇就使用工具來實戰演練對IntelliJ Idea運行速度調優程序員

調優前的運行狀態

原始配置內容

要查詢idea原始配置文件的路徑能夠在VisualVM中的概述中查看github

原始配置內容:spring

-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

打印啓動時間插件開發

須要直觀的看到優化前和優化後啓動時間的變化,因此須要簡單作一個Idea的插件開發,關於Idea插件開發的流程建議參考我之前的文章《IDEA插件:多線程文件下載插件開發 》安全

JVM的啓動時間到全部組件初始化完成後的時間就看作是IDEA的啓動時間,代碼以下微信

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, "啓動耗時", Messages.getInformationIcon());
    }
}

plugin.xml中添加以下代碼:多線程

<extensions defaultextensionns="com.intellij">
    <applicationinitializedlistener id="MyApplicationInitializedListener" implementation="cn.silently9527.MyApplicationInitializedListener" />
</extensions>

優化前的啓動信息與時間消耗

根據VisualGC和IDEA啓動插件收集到的信息:mvc

  • IDEA啓動耗時 15s
  • 總共垃圾收集22次,耗時1.2s,其中新生代GC 17次,耗時324ms; 老年代GC 5次,耗時953ms
  • 加載類27526個,耗時 21s

> 按照這個數據來看也算是正常,15s 其實也在接受範圍內,因爲本文主要演示性能調優,因此須要測試可否在快一些app

開始嘗試優化

調整內存來控制垃圾回收頻率

圖上咱們能夠看出,啓動參數指定的512m的內存被分配到新生代的只有169m,因爲IDEA是咱們開發經常使用的工具,平時的編譯過程也須要足夠的內存,因此咱們須要先把總的內存擴大,這裏我設置最大的內存-Xmx1024m,爲了讓JVM在GC期間不須要再浪費時間再動態計算擴容大小,同時也設置了-Xms1024m

在啓動的過程當中Eden共發生了17次GC,爲了減小新生代gc次數,我把新生代的內存大小設置成-Xmn256m;

從新啓動以後查看VisualGC,新生代gc次數從 17次 下降到了 7次,耗時從 324ms 下降到了 152ms。

在調整內存前發生了5次Full GC,調整內存後的依然仍是有4次Full GC,可是從兩張圖咱們能夠看出,老年代的空間還有不少剩餘,是不該該發生Full GC的;考慮是不是代碼中有地方手動調用System.gc()出發了Full GC,因此添加了參數-XX:+DisableExplicitGC,再次從新啓動IDEA,結果很失望,依然還有4次Full GC;

再次仔細觀察優化前的圖,注意看 Last Cause: Metadata GC Threshold , 最後一次gc是應該Metaspace區域內存不夠發生的GC,爲了驗證咱們的猜測,打印出GC日誌來看看。在idea.vmoptions中添加打印日誌相關的參數:

-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:../gc.log

JVM的GC日誌的主要參數包括以下幾個:

  • -XX:+PrintGC 輸出GC日誌
  • -XX:+PrintGCDetails 輸出GC的詳細日誌
  • -XX:+PrintGCTimeStamps 輸出GC的時間戳(以基準時間的形式)
  • -XX:+PrintGCDateStamps 輸出GC的時間戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
  • -XX:+PrintHeapAtGC 在進行GC的先後打印出堆的信息
  • -Xloggc:../logs/gc.log 日誌文件的輸出路徑

從新啓動idea,查看gc.log

> 其中PSYoungGen:表示新生代使用的ParallelScavenge垃圾收集器,31416K-&gt;0K(181248K)表示 gc前已使用的內存大小 -> gc後已使用內存大小(該區域的總內存大小)

從日誌中咱們看出每次Full GC都是由於Metadata GC Threshold,而Metaspace每次gc回收的內存幾乎沒有,僅僅是擴大了該區域的容量;找到了緣由那就好辦了,添加以下的參數調整Metaspace的大小:

-XX:MetaspaceSize=256m

再次重啓Idea以後,發現Full GC沒有了,心情很爽

測試打開大項目點擊編譯代碼,發現本身的idea卡死了,查看VisualGC以後發現堆內存都還有空閒,只有Metaspace被所有佔滿了,因此是本身給的最大空間設置過小,因此直接去掉了-XX:MaxMetaspaceSize=256m

選擇垃圾收集器

從剛纔的gc日誌中,咱們能夠發現默認使用的是ParallelScavenge + Parallel Old垃圾收集器,這個組合注重的是吞吐量,這裏咱們嘗試換一個注重低延時的垃圾收集器試一試

  • ParNew + CMS 在idea.vmoptions中添加以下配置:
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC

重啓IDEA以後查看VisualGC

很尷尬,一樣發生了6次gc,ParallelScavenge + Parallel Old的組合耗時197ms,而ParNew + CMS的組合耗時379ms;雖然是這個結果,可是咱們須要考慮當前只發生了MinorGC,若是發生FullGC告終果又會如何了,你們能夠本身測試一下

  • G1 咱們在換一個最新的G1垃圾回收器試試,在idea.vmoptions中添加以下配置:
-XX:+UseG1GC

這個結果好像也仍是要慢一點點,本身屢次測試過這兩個垃圾回收器,雖然每次結果都不同,相差不遠,因此垃圾回收器能夠本身選擇,這裏咱們選擇的是G1

類加載時間優化

根據以前的分析,idea啓動加載類27526個,耗時 21s,這個咱們有辦法能優化一下嗎?由於idea是經常使用的開發工具,常常不少人的使用,咱們能夠認爲它的代碼是安全的,是否符合當前虛擬機的要求,不會危害虛擬機的安全,因此咱們使用參數-Xverify:none來禁用字節碼的驗證過程

重啓IDEA

耗時降低到了11s,效果仍是比較明顯的

總結

作完了全部優化以後,通過屢次重啓測試,平均的啓動時間降低到了11s,爲了安慰我本次操做沒有白辛苦,搞一張11s如下的圖


寫到最後(點關注,不迷路)

文中或許會存在或多或少的不足、錯誤之處,有建議或者意見也很是歡迎你們在評論交流。

最後,白嫖很差,創做不易,但願朋友們能夠點贊評論關注三連,由於這些就是我分享的所有動力來源🙏

原創不易 轉載請註明出處:https://silently9527.cn/archives/102


我已經從零開始手寫了簡易版springmvc,以及編寫了詳細的說明文檔,但願可以幫助夥伴們深刻理解springmvc核心原理,有須要的朋友歡迎關注公衆號:貝塔學JAVA ,回覆源碼便可

相關文章
相關標籤/搜索