簡(jiǎn)書 占小狼
轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處,謝謝!
如果讀完覺得有收獲的話,歡迎點(diǎn)贊加關(guān)注
周末愉快,今天有時(shí)間記錄一下上周遇到的一個(gè)問題,學(xué)習(xí)的腳步不能放慢,也不敢放慢。
存在問題
在線上環(huán)境進(jìn)行服務(wù)壓測(cè),壓測(cè)完成后,cpu使用率居高不下,很是費(fèi)解,按理說已經(jīng)沒有壓測(cè)請(qǐng)求了,這時(shí)消耗cpu資源的只有GC線程了,可以通過jstat
命令查看一下JVM的GC情況,然后就碰到了詭異的GC問題。
jstat命令
jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]
參數(shù):
generalOption: 一般使用-gcutil查看GC情況
vmid: 虛擬機(jī)進(jìn)程號(hào),即當(dāng)前運(yùn)行的java進(jìn)程號(hào)
interval: 間隔時(shí)間,單位為秒或毫秒
count: 打印次數(shù),如果缺省則打印無數(shù)次
執(zhí)行jstat -gcutil 9132 1000
命令,線上服務(wù)器的GC情況如下:
參數(shù)說明如下:
S0: 新生代中Survivor space 0區(qū)已使用空間的百分比
S1: 新生代中Survivor space 1區(qū)已使用空間的百分比
E: 新生代已使用空間的百分比
O: 老年代已使用空間的百分比
P: 永久帶已使用空間的百分比
YGC: 從應(yīng)用程序啟動(dòng)到當(dāng)前,發(fā)生Yang GC 的次數(shù)
YGCT: 從應(yīng)用程序啟動(dòng)到當(dāng)前,Yang GC所用的時(shí)間【單位秒】
FGC: 從應(yīng)用程序啟動(dòng)到當(dāng)前,發(fā)生Full GC的次數(shù)
FGCT: 從應(yīng)用程序啟動(dòng)到當(dāng)前,F(xiàn)ull GC所用的時(shí)間
GCT: 從應(yīng)用程序啟動(dòng)到當(dāng)前,用于垃圾回收的總時(shí)間【單位秒】
問題分析
通過打印的GC數(shù)據(jù)可以看出,JVM一直在進(jìn)行FGC(cms gc),不過老年代的使用率反而沒有下降,一直穩(wěn)定在60.16%,對(duì)這一情況很疑惑,幾乎每次都重現(xiàn),后來去仔細(xì)查看了JVM的啟動(dòng)參數(shù),發(fā)現(xiàn)其中CMSInitiatingOcupancyFraction
參數(shù),被設(shè)置成60,意味著當(dāng)老年代的使用率達(dá)到閾值60%時(shí)會(huì)觸發(fā)FGC,但是FGC之后,老年代的使用率還是大于60%,所以會(huì)不斷的進(jìn)行FGC,建議這個(gè)值不要設(shè)置的這么小。
至于為什么FGC之后,老年代的使用率沒有下降,可以通過dump查看到底是哪些存活對(duì)象在作怪,在進(jìn)行FGC時(shí),通常會(huì)伴隨著一次YGC,但這也不是一定的,如果執(zhí)行YGC之后沒有明顯效果的話,會(huì)設(shè)置一個(gè)變量,表明下次不用進(jìn)行YGC,所以如果老年代如果存在大量對(duì)象的GC ROOT在新生代的話,這些對(duì)象就不會(huì)被回收,這種情況必須強(qiáng)制執(zhí)行一次YGC之后,才有可能回收這些老年代的對(duì)象,比如添加參數(shù)-XX:+CMSScavengeBeforeRemark
,就可以解這個(gè)問題。
昨天正好笨神也遇到類似的問題,并寫一篇文章《又抓了一個(gè)導(dǎo)致頻繁GC的鬼--數(shù)組動(dòng)態(tài)擴(kuò)容》進(jìn)行分析,可以參考一下。