mixedGc在G1垃圾回收器永遠不會發生


從生產環境得到的結論:開啟了g1垃圾回收器,如果使用默認G1配置,則mixedGc永遠不會發生。

參考文檔openJdk官網討論該bug的鏈接stackoverfloa討論該bug的鏈接

原因:jdk8的G1垃圾回收器默認參數配置有bug,需要自己調整InitiatingHeapOccupancyPercent參數。

A、G1垃圾回收器的開始mixedGc的閾值InitiatingHeapOccupancyPercent默認是45%,這指的是已經使用內存(老年代+新生代)占整個堆的占比。

B、G1MaxNewSizePercent的默認值是60%

C、G1垃圾回收期與之前的垃圾回收器的回收模型(和內存區域划分)如此不同,所以執行機制也很不同,執行一次ygc后,會計算是否達到InitiatingHeapOccupancyPercent,如果達到,則觸發mixedGc。在ygc后再判斷的機制,導致實際的計算是:老年代使用/整個堆。

而老年代最多達到100%-60%=40%,所以永遠無法觸發mixedGc,會在老年代達到97%使用率或者沒有連續分配空間時直接觸發fullgc。

 

回顧生產事件:

1、生產內存告警后,去生產執行jmap -heap命令,查看堆內內存最高使用率為87%,但尚未達到fullGc條件(jdk8中老年代使用97%會觸發fullGc)。加上堆外內存幾百M,達到了虛擬機的告警條件。

2、換用G1垃圾回收器,指望InitiatingHeapOccupancyPercent觸發mixedGc,來阻止告警。

3、發現依舊告警,一方面了解到InitiatingHeapOccupancyPercent的深坑。

4、另一方面,在同事雲神的提示下,開始理不直也氣壯了:雖然我們有坑,但我們也有fullGc保底,不會oom,為啥多吃幾百M內存,就告警。對比了下別人不告警的機器,機器分配內存都比我們大,計算了下如果同樣配置我們也可以不告警。於是和運維同事一起計算后,一致同意幫我們加內存。

 

另外,細節總結如下——

1、我們沒有內存泄露:在生產通過jmap -dump:live, format=b,file=<filename> <pid>命令打dump文件,順便執行一次FullGc,老年代瞬間從15N變為N。腰桿都直了,說話分貝都提升了些。

2、我們所有計算都與內存告警圖相符,計算過程:

A、機器內存使用率上升=(此刻堆外內存+堆內使用內存)-(應用啟動時堆外內存+堆內使用內存)/機器總內存=老年代增長/機器總內存

B、堆外內存+堆內使用內存=ps aux命令RSS列相加=top命令內存使用

C、堆內使用內存=gc日志中總used=jmap -heap 命令中的G1 heap used=jmap -heap 命令中的老年代使用+新生代使用

D、老年代增長=jmap -heap的old值=此刻ygc高點-應用啟動時ygc高點=此刻ygc低點=應用啟動時ygc低點

4、分析老年代增加過快,所以告警往往幾天就來了。

使用mat工具分析dump文件,意外發現job引用對象在老年代中最大,老年代增長迅速原因總結如下,我們是C導致的:

A、大對象巨型對象,會直接進入老年代
B、GC日志中提升失敗:一般是survivor區域配置過小或者新生代配置過小導致的。小概率是ygc頻繁,但限定了ygc執行時間於是直接晉升老年代。
C、對象存活過久:一般是守護線程中的一些對象,或者其它場景下對象被長時間引用,ygc次數超過MaxTenuringThreshold,則進入老年代。我們job撈取幾百筆數據,等全部處理完才釋放,存活過久。
D、內存泄漏:如果內存泄漏,老年代的使用率居高不下,fullGC也無法回收。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM