最近線上服務運行比較緩慢,老大提出讓我進行JVM優化。GC的內容很多,也不可能一時間全部都掌握,今天就要看看G1的一些知識,還有調優時可調整的參數。
1.G1簡介
G1的全稱為 Garbage First Garbage Collector, 是一款內置在HotSpot JVM中的服務端垃圾收集器。
G1是作為CMS的替代產品出現的,其目標是在滿足最短時間停頓的同時達到一個高吞吐量,適用于多核處理器,大內存容量的系統。
其特點如下:
- 短停頓時間且可控。對內存進行分區,可以應用在大內存系統中,其使用了基于內存的新生代收集和混合收集。
- 高吞吐量。設計了新的并發標記線程,并發處理分區之間的引用關系,加快垃圾回收速度。
1.1分區
G1垃圾回收器將堆內存劃分成固定大小的Region,下圖為G1內存的分配示意圖,其中灰色格子代表一個region。
其中G1的分區可以分為4類:
- 自由分區(Free Heap Region, FHR)
- 新生代分區(Young Heap Region , YHR) 新生代也分為Eden 和Survivor區
- 大對象分區(Humongous Heap Region,HHR) 大對象區可分為 大對象頭分區和大對象連續分區,大對象一般占Region的一半以上。
- 老生代分區(Old Heap Region,OHR)
img
Region可以在1MB~32MB,且為2的N次冪,設定分區大小有以下方法:
- 可以通過-XX:G1HeapRegionSize=<>來指定大小,默認為0.
- 默認情況下是將整個堆分為2048個Region。
1.1.1 新生代大小
新生代大小的設置如下:
- 如果設置了最大值 (MaxNewSize) 和最小值(NewSize), Xmn 等價于MaxNewSize
- 如果設置了最大值和最小值,又設置了NewRatio 則忽略NewRatio
- 如果沒有設置新生代最大值和最小值,但是設置了NewRatio 則新生代的最大值最小值是相同的,都是整個堆空間的 (NewRatio+1)
- 如果沒有設置新生代最大值和最小值,或者只設置了最大值或者最小值中的一個,那么G1將根據參數G1MaxNewSizePrecent(默認值60) 和 G1NewSizePercent (默認值5)占整個堆空間的比例計算最大值和最小值。
關于堆大小的參數優化:
- G1HeapRegionSize 可以指定堆的大小,可指定也可以有內存管理啟發推斷分區大小。
- xms/xmx 指定堆空間的最小值/最大值, 一定要設置正確的值,否則會影響分區大小推斷。
- G1不要設置MaxNewSize,NewSize,Xmn, NewRatio,即不要顯示的設置年輕代的大小 。G1對內存的管理不是連續的,所以即使重新分配一個堆分區的代價不大;G1的目標滿足垃圾收集停頓,這需要G1根據停頓時間動態調整收集的分區,如果設置了固定的分區數,G1不能調整新生代的大小,則不容易滿足停頓時間的需求。
- GCTimeRatio指的是GC與應用程序之間的時間占比,默認值是9,表示GC與程序的時間占比為90%,增大該值將減少GC占用時間,增大該值則動態擴展內存會更容易發生。
2.G1 GC可優化參數
G1提供了兩種GC模式,Young GC 和 Mixed GC 兩種GC都會有STW.
Young GC
主要是對Eden區進行GC ,一般情況下,會在Eden Region使用達到最大閾值時,空間內存不夠用時,觸發YoungGC。每次Young GC會回收所有的Eden 和Serviour區,并且將存活對象復制到Old區以及一些Survivor區。
Mixed GC
Mixed GC 會選取(并發標記)所有的 Young Region和 回收收益較高的一些 Old Region, 然后進行年輕代回收算法。
混合回收分為兩個階段。
- 并發標記
- 垃圾回收
其中并發標記階段可以分為以下幾個子階段:
- 初始標記子階段:標記所有直接可達的根對象,此階段會STW,
- 并發標記子階段:YoungGC 執行完成之后,如果滿足并發標記的的條件(已分配及將要分配的內存占總內存的比例超過閾值之后),就進行并發標記,其中-XX:ConcGCThreads 控制并發標記線程數量,一個線程每次掃描一個Region。此時標記存活對象,
- 再標記子階段:找出所有未被訪問的存活對象,此過程為并發執行,并且會有STW,其中-XX:ParallelGCThreads可指定GC暫停時可用的GC線程數。
- 清理子階段:需要STW,存活對象計數,整理標記位圖,釋放完全空閑的分區。
混合回收階段的參數優化:
- 參數InitiatingHeapOccupancyPercent(IHOP),默認值時45, 此值時啟動并發標記的先決條件,只有已分配內存占總空間超過45%之后,才會啟動并發標記任務。增加此值,將導致并發標記可能花費更多的時間,也會讓YGC或者MixedGC時收集的分區變少,這樣就會導致更多的Full GC。這個值可以根據整體應用占用的平均內存來設置,可以把該值設置的比平均內存稍微高一點。IHOP的設置效果很明顯,但是要設置合理的值并不容易,需要更多的性能測試來判斷。
- 參數G1ReservePercent, 默認值是10,如果GC晉升失敗導致FullGC,則可以調大該值
- 參數ConcGCThreads為并發線程數,默認值為0,如果未設置,可以動態調整,并且使用ParallelGCThreads為依據來推斷,如果并發標記耗時較大,可以增大并發線程數。
- HeapSizePerGCThread 默認為64M,表示每64M分配一個線程
- 參數UseDynamicNumberOfGCThreads,默認為false,設為true表示可以動態調整線程數,調整范圍會根據最大線程數,HeapSizePerGCThread確定。
- 參數GCDrainStackTargetSize,默認值為64,表示并發標記子階段,一次標記最多標記的最多對象個數。
- 參數GCMixedGCLiveThresholdPercent 默認值85,用于判斷分區能否被加入到CSet中,低于該值將會被加入。
- 參數G1HeapWastePercent 默認值5,即當Cset中可回收空間 占總空間的比例大于G1HeapWastePercent才會開始混合回收。
- 參數G1MixedGCCountTarget,默認值為8,這個參數越大,收集老年代的分區越少,反之收集的分區就越多,盡量保持老年代分區在Cset中的比例超過1/G1MixedGCCountTarget。
- 參數G1OldCSetRegionThresholdPercent 默認值為10,表示最多收集10%的分區。
- 參數G1ConcMarkStepDurationMillis 默認值為10,表示每個并發標記子階段最多執行10ms
FullGC發生之后,基本都是串行回收. 如果不幸發生了FullGC, 那么我們能做的就是盡量讓FullGC盡快完成,然后降低其頻率。但是通常情況下,比較固定且較長時間間隔的FullGC是被允許的。
那么FullGC相關也是有一些優化調整的地方:
- 使用參數MinHeapFreeRatio 用于判斷是否可以擴展堆空間,增大該值擴展的概率就會變小。
- MaxHeapFreeRatio 判斷是否可以收縮空間,增大該值收縮的概率也會變小。
- MarkSweepAlwaysCompactCount 默認值為4,這個值表示經過一定次數的GC之后,允許當前區域中一定比例的死亡對象當作存活對象處理,暫時不回收,從而加快FullGC的處理流程。這個比例可以使用MarkSweepDeadRatio來修改,默認值為5.
總結
以上是一些優化參數的使用,至于具體調優的目的要根據我們各個程序的要求。一般而言需要滿足最大的吞吐量和最小的暫停時間,GC頻率盡量低,堆空間的有效利用率高等。可調整的部分有內存參數的優化,引用的處理(Rset),并發標記(Mark),垃圾回收部分。
Oracle官方有一些推薦調優的方向:
- 針對年輕代的設置,盡量避免明確的設置年輕代的大小(使用-Xmn,-XX:NewRatio等),固定的年輕代大小會覆蓋最小停頓時間的目標。
- 對于暫停時間的目標,我們需要考慮平衡延遲和吞吐量,兩者不可兼得,所以需要找到一個最佳的平衡點。
- 混合回收階段的優化參數可以考慮率使用 -XX:InitiatingHeapOccupancyPercent 修改內存占用比(具體可以參考前文), -XX:G1MixedGCLiveThresholdPercent 和 -XX:G1HeapWastePercent 改變混合垃圾回收的策略,-XX:G1MixedGCCountTarget 和 -XX:G1OldCSetRegionThresholdPercent 調整老年代在CSet中的占比
-
參數
+關注
關注
11文章
1791瀏覽量
32110 -
應用程序
+關注
關注
37文章
3245瀏覽量
57614 -
線程
+關注
關注
0文章
504瀏覽量
19653 -
服務端
+關注
關注
0文章
66瀏覽量
6989 -
G1
+關注
關注
0文章
2瀏覽量
2319
發布評論請先 登錄
相關推薦
評論