記錄一次Metaspace擴容引發FGC的調優總結
- 2019 年 10 月 17 日
- 筆記
開始之前
在開始之前先記錄一個我碰到的jvm調優的坑。那就是…
為啥我配置到idea64exe.vmoptions中的參數沒有生效???
由於之前一直是在mac上開發,本地開發時當需要優化jvm參數的時候直接去idea的安裝目錄里修改idea.vmoptions就可以了,換到windows以後想當然的也這麼改,但是發現似乎我配置的參數並沒有生效, what‘s the f***?探索了一番終於發現了問題所在。
windows是基於用戶登錄的,idea會為每個用戶在當前用戶根目錄下創建一份配置資訊,所以在idea安裝目錄下修改idea.vmoptions是不生效的,如圖:
不知道管理員用戶登錄的話是不是就可以直接修改idea安裝目錄的ideaexe.vmoptions了,有一個很簡單的方法判斷你當前的idea項目使用的是哪裡的配置資訊。
發現問題
ok,現在終於可以優化我們的jvm參數了,下面是一套我經常用的參數,在我以前開發的時候基本都是用這套參數,我也就直接複製到了idea64exe.vmoptions。
-Xms1024m -Xmx1024m -Xmn512m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -XX:ReservedCodeCacheSize=512m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow
保存重啟idea以後,開一個項目,嗯,沒啥感覺,一切正常。開兩個項目,嗯,怎麼有點卡呢。又開了一個項目,噩夢開始了,idea開始爆卡,點一下卡2s的那種。
定位原因
-
jps:查看idea platform的進程ID
-
jstat -gcutil pid 3s:查看進程垃圾回收情況
從上圖可以看出,剛開始YGC和FGC都很健康,但隨著我打開的項目越來越多,FGC開始飆升,直接導致了頁面明顯的卡頓,我試著關掉了幾個項目,只保留一個,FGC慢慢變小,分析上圖可以看出,M的佔比隨著FGC略有下降,從93.7%下降到93.2%左右,推測可能是Metaspace擴容導致的FGC。
確認原因
通過jstat -gc pid 3s:可以查看metaspace具體使用情況,下圖可以看出metaspace發生了擴容。
更簡單的是,通過命令jvisualvm,打開Java VisualVM查看mataspace具體使用大小。
果然,當我同時打開多個項目時,metaspace發生了擴容,並且最終mataspace的使用量達到了接近250M,幾乎達到了上面我配置的參數-XX:MetaspaceSize=256m,於是我將上面配置中關於mataspace的參數刪掉。
-Xms1024m -Xmx1024m -Xmn512m -XX:ReservedCodeCacheSize=512m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow
再次jstat -gcutil pid 3s查看GC情況。
這次FGC情況大有改善,隨著我開的項目越來越多,FGC也只是從6次漲到了8次。至此,問題基本就解決了,但如果只是這樣的話,我寫這篇筆記的意義就不大了,接下來的才是重點。
深入探究
我嘗試重新添加了mataspace的參數,如下:
-Xms1024m -Xmx1024m -Xmn512m -XX:MetaspaceSize=384m -XX:MaxMetaspaceSize=384m -XX:ReservedCodeCacheSize=512m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow
再次jstat -gcutil pid 3s查看GC情況:
上圖是我同時開了5個項目的GC情況,FGC只有1次,這才是讓我覺得困惑的地方,也就是說當我設置了MetaspaceSize=384m和不設置的時候,是有區別的,在網上看了很多關於mataspace的文章,我發現自己一直以來都沒有搞懂-XX:MetaspaceSize=256M的真正含義,這個配置的含義並不是初始化元數據區大小為256m,而僅僅表示的是觸發FGC的閾值,至於配置和不配置的區別,也就很明顯了,這個知識點在書上看到過但是沒放在心上,在實際碰到問題的時候才恍然大悟。
Metaspace由於使用不斷擴容到-XX:MetaspaceSize參數指定的量,就會發生FGC;且之後每次Metaspace擴容都可能會發生FGC。
我們知道Metapsace是在jdk8中引入的,之前叫permGen,就是我們所說的永久代。在jdk8以前,我們配置-XX:PermSize=256m,那就是說初始化一塊256m的記憶體作為永久代。但是mataspace就不一樣了,很明顯,mataspace要比perm高級的多。
總結
-
如果沒有配置-XX:MetaspaceSize,那麼觸發FGC的閾值是21807104(約20.8m)。
-
如果配置了-XX:MetaspaceSize,那麼觸發FGC的閾值就是配置的值。
-
配置比不配置好,實際開發時,可以先開幾個項目查看一下metaspace大概佔用多少記憶體,這個跟項目大小和複雜度有關,再根據實際情況配置-XX:MetaspaceSize。
查看當前java進程,一般用來查找進程ID(PID)
- jps:查看當前java進程及PID
- jps -l:輸出主類或者jar的完全路徑名
- jps -v:輸出jvm參數
動態查看gc情況
- jstat -gc pid 3s: 每隔3s列印當前pid進程的堆記憶體詳細資訊
- jstat -gcutil pid 3s: 每隔3s列印當前pid進程的堆記憶體總體GC統計資訊
可視化工具jvisualvm
命令行直接輸入jvisualvm可打開可視化工具,動態查看java進程內部詳細資訊
結合以上3種途徑,可以查看java進程的詳細使用情況和GC情況。