事件背景:
同事向我咨詢了從jvm監控中看到的現象,大致描述就是:young gc 頻繁,但是沒有full gc,且堆內存一直保持在近100%的狀態,線程變化穩定,CPU的使用率有波動,主要和young gc有關,具體情況見下圖1。然后我們就去運維平台,通過jmap平台查看堆內存的使用情況,前面的數據看起來正常,可是在看concurrent mark-sweep generation的時候,數據不正常,如圖2。
圖1
圖2
運維反饋,此為一個bug,官方給出了解釋:
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8033440
大致的意思是使用jdk8、cms gc背景下, 使用jmap命令去查看堆內存的使用情況時,由於計算的差異會導致該問題,解決的方案是更換gc策略(官方解釋的有提到),也許更換命令也是可以的。
后續沒有深入研究,可能還存在別的處理方案,也可能我對官網的解釋有誤解,所以僅作參考。
后續深入研究的時候,再補充更新。
關於同事咨詢的問題,其實很快就找到了原因:
1、GC策略是 ParNew GC + CMS GC,物理內存是8G,jvm參數配置了-Xmx5120m,-Xms與之相等,即jvm最大的堆內存是5G,old區約4787MB,young區約333M。由於young 區空間太小,導致了頻繁的young gc。
2、加上jvm參數還配置了-XX:+UseCMSInitiatingOccupancyOnly ,但是沒有配置-XX:CMSInitiatingOccupancyFraction=80,jvm就默認old區已用空間達到92%的時候,才會觸發full gc,如果沒有達到這個閾值,就不會出現full GC,堆內存的使用就會越來越大,就出現了圖片的那個情形,當然還存在別的觸發full GC的情況,這里就先不做過多闡述,如果該機器一直這樣下去,肯定也會出現full GC。
3、使用jmap命令查看堆內存的使用情況時,還看到了這個參數-XX:NewRatio,默認的值為2,但是很明顯並沒有起作用,經網上搜索,有人說CMS GC中,這個參數默認是不起作用的,需要手工設置,而且如果手工指定了年輕代和整個堆內存的大小后,也是不起作用的。
解決方案:
1、手工設置年輕代的大小和整個堆內存的大小,我們設置為1g
2、設置CMS full GC的閾值 為80,即配置-XX:CMSInitiatingOccupancyFraction=80
處理結果:效果明顯