G1回收器
在使用ParNew + CMS進行垃圾回收時,會導緻長時間的
STW
,而STW的本質就是停止系統的工作線程,讓系統無法對外服務,同時讓GC線程進行垃圾回收的。如果回收時間較長,那麼會給系統性能帶來較大的影響
是以G1回收器出現了,它的特點有
- 将Java堆分為多個大小相等的
Region
- 每個
都有可能屬于新生代或老年代Region
- 可以設定
,比如在一小時内最多停頓一分鐘垃圾回收的預期停頓時間
G1如何做到設定 垃圾回收的預停頓時間
垃圾回收的預停頓時間
G1會追蹤每個
Region
中的
回收價值(目前Region中有多少垃圾對象,需要耗費多長時間)
,通過追蹤,G1可以比較出本次回收哪些
Region
的成本效益最高(時間最短,回收記憶體最多),在有限的時間内盡可能回收掉更多的垃圾對象
如何啟用G1回收器
可以通過JVM參數
-XX:UseG1GC
來指定垃圾回收器為G1
如何設定G1的記憶體大小
在指定了G1回收器後,它會根據
-Xmx/2048
來計算每個Region的記憶體大小,因為JVM中最多支援2048個Region,并且每個Region的記憶體必須是2的倍數
比如你設定的
-Xmx4096M
,那麼按照G1的規則來,4096 / 2048 = 2MB,那麼每個Region的記憶體大小就為2MB
當然,你也可以手動通過JVM參數
-XX:G1HeapRegionSize
來指定每個Region的大小
系統初始化狀态,新生代的記憶體占比為5%,大概為100個Region,可以通過JVM參數
-XX:G1NewSizePercent
來設定這個比例,但是一般都推薦保持這個設定,因為G1會動态的調整新生代、老年代的記憶體占比,但是預設情況下新生代的最大占比不能超過
60%
,可以通過JVM參數
-XX:G1MaxNewSizePercent
來設定這個比例
G1中新生代還保留着Eden、Survivor的劃分
雖然G1回收器将記憶體分為了多個Region,但是新生代依舊保留着原本的區域劃分,即Eden、Survivor1、Survivor2,并且預設情況下它們的比例為
8:1:1
,可以通過JVM參數
-XX:SurvivorRatio
來設定比例,比如系統初始化時,新生代大約有100個Region,那麼其中大約有80個Region是Eden區的,10個Region是S1區的,10個Region是S2區的
G1中新生代的垃圾回收算法
G1中新生代在Eden區滿時會觸發GC,垃圾回收算法還是使用
複制算法
,同時進入
STW
,但是因為G1設定了預期停頓時間,可以讓系統在GC時指定最多停頓的時間,而不像ParNew回收器那樣,極端情況下能夠一直停頓,而對系統性能造成嚴重影響
可以通過JVM參數
-XX:MaxGCPauseMills
來設定這個時間
G1中對象什麼時候進入老年代
和原來一樣,進入老年代的條件有,
-
,預設為15年,通過JVM參數超過指定年齡的對象
指定這個門檻值-XX:MaxTenuringThreshold
-
,當某一年齡動态年齡判斷
的對象占有了新生代記憶體的以下(包括)
以上,那麼所有超過該年齡的對象都會進入老年代50%
- 新生代GC後,存活對象記憶體大小超過Survivor區記憶體大小,這些對象會進入老年代
G1中如何處理大對象
在G1中,大對象不會進入老年代,G1會提供專門的Region來存放這些大對象
G1中大對象的判定規則為:該對象超過了一個Region大小的50%,那麼這個對象就是大對象
大對象可能會橫跨多個Region
G1中大對象的回收
會在新生代、老年代發生GC時順帶回收掉
什麼時候觸發新生代、老年代混合垃圾回收
JVM參數
-XX:InitiatingHeapOccupancyPercent
,預設為45,即當老年代占堆記憶體比例達到45%時,即Region數量大約為1000個時,會嘗試觸發一個混合回收
Mixed GC
G1回收器的回收過程
- 初始标記
- 并發标記
- 最終标記
- 混合回收
初始标記
和CMS一樣,這個步驟會觸發
STW
,此時會标記那些被
GC Roots
直接引用的對象,比如靜态變量,局部變量等
并發标記
這個步驟,工作線程和GC線程會同時工作,此時會追蹤所有存活的對象,同時JVM會對這個步驟中對象的一些修改記錄起來,比如哪個對象被建立了,哪個對象失去了引用等
最終标記
這個步驟會觸發
STW
,對并發标記階段記錄的被修改的對象進行最終标記,找出存活對象和垃圾對象
混合回收
這個步驟會計算老年代中每個Region中存活的對象數量,存活對象的占比和執行垃圾回收的預期性能和效率,然後停止工作線程,對部分Region進行回收,因為G1需要控制垃圾回收時的停頓時間(使用者指定)
混合回收的區域包括新生代、老生代和大對象Region
這個階段會執行多次,JVM參數
-XX:G1MixedGCCountTarget
指定了混合回收執行的次數,預設為8次,每執行完一次會啟動工作線程對外提供服務,一段時間後繼續進行
STW
,執行混合回收,這樣可以盡可能的讓系統停頓的時間變短,盡量減少對象系統性能的影響
JVM參數
-XX:G1HeapWastePercent
,預設為5,當G1中Region空閑比例達到5%時,混合回收就結束了
在混合回收時,對Region的回收都是基于
複制算法
的,即把Region中的存活對象複制到其他Region中,然後清理掉目前Region中的垃圾對象,那麼G1回收器進行垃圾回收時,是不會産生記憶體碎片的
JVM參數
-XX:G1MixedGCLiveThresholdPercent
,預設為85,G1回收器在确定回收Region時,必須要保證該Region中的存活對象在85%以下,否則使用複制算法的回收效率是非常低的
當G1回收失敗時,如在回收時拷貝對象的時候,回收器發現沒有空閑的Region可以放入存活對象了,那麼就會觸發一次回收失敗,失敗之後,JVM就會切換到單線程回收器,進行标記-清理,壓縮和整理,空閑出一批Region,這個過程是非常慢的,又因為它是需要
STW
的,是以對系統的性能影響非常大