天天看點

JVM:25 線上系統部署采用G1垃圾回收器,如何設定參數?

1. 什麼時候出發新生代 + 老年代的混合垃圾回收?

G1 有個參數,是 “-XX:InitiatingHeapOccupancyPercent” ,預設值是45%。意思是老年代占據了堆記憶體的45%的 Region時,就會觸發一個新生代 + 老年代一起回收的混合回收階段。

2. G1垃圾回收的過程

首先會觸發一個 “初始标記” 操作,這一過程需要進入 STW,但僅僅是标記一下 GC Roots 直接能引用的對象,速度是很快的。

整個過程是,先停止系統程式的運作,然後對各個線程棧記憶體中的局部變量代表的 GC Roots,以及方法區中的類靜态變量代表的 GC Roots,進行掃描,标記出來他們直接引用的那些對象。

JVM:25 線上系統部署采用G1垃圾回收器,如何設定參數?

接着會進入 “并發标記” 的階段,這個階段會允許系統程式的運作,同時進行 GC Roots追蹤,從 GC Roots 開始追蹤所有的存活對象。

JVM:25 線上系統部署采用G1垃圾回收器,如何設定參數?

 JVM會對并發标記階段對象作出的一些修改記錄起來,比如說哪個對象被建立了,哪個對象失去了引用。

接着是下一個節點,最終标記階段,這個階段會進入 “STW” ,系統程式是禁止運作的,但是會根據并發标記階段記錄的那些對象修改,最終标記一下有哪些存活對象,有哪些是垃圾對象,如下圖:

JVM:25 線上系統部署采用G1垃圾回收器,如何設定參數?

最後一個階段,就是 “混合回收” 階段,這個階段會計算老年代中每個 Region 中的存活對象數量,存活對象的占比,還有執行垃圾回收的預期性能和效率。

接着會停止系統程式,然後全力以赴盡快進行垃圾回收,此時會選擇部分 Region 進行回收,因為必須讓垃圾回收的停頓時間控制在我們指定的範圍内。

JVM:25 線上系統部署采用G1垃圾回收器,如何設定參數?

而且,由于老年代對堆記憶體占比達到 45% 的時候,觸發的是 “混合回收”。也就是說,此時垃圾回收不僅僅是回收老年代,還會回收新生代,還會回收大對象。

根據情況,因為設定了對 GC 停頓時間的目标,是以說他會從新生代、老年代、大對象裡各自挑選一些Region,保證用指定的時間(比如200ms) 回收盡可能多的垃圾,這就是所謂的混合回收。

JVM:25 線上系統部署采用G1垃圾回收器,如何設定參數?

 3. G1垃圾回收器的一些參數

G1回收器進行垃圾回收的最後一個階段混合回收的時候,會執行 STW,是以說G1是允許執行多次混合回收的。

比如先停止工作,執行一次混合回收掉一些 Region,接着恢複系統運作,然後再次停止系統運作,再執行一次混合回收掉一些 Region。

有個參數,“-XX:G1MixedGCCountTarget” 參數,預設值為8。表示在一次混合回收的過程中,最後一個階段執行幾次混合回收。即可以不間斷地反複執行8次混合回收。

為什麼要反複回收多次呢?

因為停止系統一會兒,回收掉一些 Region,再讓系統運作一會兒,然後再次停止系統一會兒,再次回收掉一些 Region,這樣可以盡可能讓系統不要停頓時間過長,可以在多次回收的間隙,也運作一下。

還有另一個參數,“-XX:G1HeapWastePercent” ,預設值為 5%。意思是在混合回收的時候,對 Region 回收都是基于複制算法進行的,都是要回收的 Region 裡的存活對象放入其他 Region,然後這個  Region 中的垃圾對象全部清理掉。

JVM:25 線上系統部署采用G1垃圾回收器,如何設定參數?

這樣在回收過程就會不斷空出來新的 Region,一旦空閑處理的 Region 數量達到了堆記憶體的 5%,此時就會立即停止本次混合回收。

G1整體是基于複制算法進行 Region 垃圾回收的,不會出現記憶體碎片的問題,不需要像 CMS 那樣标記 - 清理之後,再進行記憶體碎片的整理。

還有一個參數,“-XX:G1MixedGCLiveThresholdPercent” ,它的預設值是 85%,意思是确定要回收的 Region 的時候,必須是存活對象低于 85%的 Region 才可以進行回收。否則,回收成本就很高。

4. 回收失敗時的Full GC

如果在進行Mixed回收的時候,無論是年輕代還是老年代都基于複制算法進行回收,都要把各個Region的存活對象拷貝到别的 Region裡去。

如果拷貝的過程中發現沒有空閑 Region 可以承載自己的存活對象,就會觸發一次失敗。

一旦失敗,就會立刻切換為停止系統程式,然後采用單線程進行标記、清理和壓縮整理,空閑出來一批 Region,這個過程是極慢極慢的。