1. 背景
偶然發現查看線上日誌-Xloggc:******/gc.log下面的日誌,發現線上機器存在Full GC,查找其他服務發現都會有這個問題,
基於我們系統很多垃圾回收機制都是ParalllelGC,即吞吐量優先GC方式,GC線上在處理任務時會造成系統stop the wrold暫停,而且GC
時間相對CMS等收集器而已要更長,雖然這些Full GC暫時無明顯停頓,但是出於優化原則進行了一輪排查。下面是對幾臺線上機器的比對。
比對發現線上服務最後一次啓動時間與FullGC出現時間相對吻合。
2. 問題定位
通過觀察比對發現這些Full GC有幾個比較明顯的特點
- 每臺機器都有幾個Full GC ,這幾個Full GC的時間間隔並不長
- 線上xmx是2g,由新生代佔比3/8的比例看,Full GC產生時PSYongGen ParOldGen並無達到造成Full GC的大小
- 將日誌第一次觸發Full GC時間和該服務最後一次啓動時間對比,發現幾乎吻合
- Full GC類型屬於Metadata GC Threshold(jdk 1.8纔會打印類型)
有次四點,我們可以總結到本次Full GC是由服務時啓動導致的,由於jdk1.8開始jvm用metaspace替代Perm永久區,我們知道永久區是用來存儲已被虛擬機加載的類信息,
常量和靜態變量,然後跑去寒泉子大牛的JVMPocket看到,jdk從1.6到1.8的默認大小都是MetaSpaceSize=21807104字節(20.8M左右),繼續觀察我們會發現這幾次
Full GC前後,Metaspace的使用變化是從20844k→20844k,也就是並沒有發生變化,看起來好像Metaspace並沒有被回收,其實這是JVM的一個BUG,alijdk等自用產品
會將這個問題進行了修復,能看到前後是有變化的,所以如果大家在排查Metaspace的問題時候,希望不要被這個信息騙到
3. mat分析內存使用情況
gc前
gc後
我們發現gc前後內存使用情況並無明顯變化,再查看了一下Leak Suspect發現使用內存較多的類是java.lang.ref.Finalizer,此類在finally做流關閉會大量存在,
由於我們用的是dubbo做遠程過程調用,故也屬於正常行爲。
4. 大結局
到這裏,我們看到還是MetaSpaceSize設置太小的問題導致,查看參考配置發現很多公司會將MetaSpaceSize設置爲128M,在dev重現了此問題後,設置成
128M,重新看gc日誌並未發現有Full GC問題,到此,我們就成功解決了線上一個Full GC問題。