java中的g1_G1GC 概念与性能调优
本文來自OPPO互聯網技術團隊,轉載請注名作者。同時歡迎關注我們的公眾號:OPPO_tech,與你分享OPPO前沿互聯網技術及活動。本文不討論 G1 底層數據結構與算法,從 G1 GC 行為上做簡要介紹 G1 的過程
Garbage-First Garbage Collector 從官網的描述來看:
G1 is a generational, incremental, parallel, mostly concurrent, stop-the-world, and evacuating garbage collector which monitors pause-time goals in each of the stop-the-world pauses. Similar to other collectors, G1 splits the heap into (virtual) young and old generations. Space-reclamation efforts concentrate on the young generation where it is most efficient to do so, with occasional space-reclamation in the old generation.
從介紹可以加粗幾個重點分代
并發
STW
在每個STW階段關注暫停時間目標
回收主要集中在最有效的young generation, old generation則沒這么頻繁
在G1中,為了提升吞吐量,有一些操作永遠是(STW) stop-the-world 的。其他的一些要長期的,如全局標記這種要全堆進行的操作與應用程序并發進行。為了讓空間回收的 STW 盡可能減少,G1并行的分步的遞增進行空間回收。G1通過追蹤此前應用行為和垃圾回收停頓的信息來構建一個與開銷有關的模型(Pause Prediction Model)。它使用這些信息停頓期間可做的工作。舉個例子,G1首先回收最高效的區域(也即垃圾最滿的區域,因此稱為垃圾—優先)。
堆
G1把堆分成了n個大小相同的region
E 是 eden region
S 是 survivor region
O 是 old region
H 是 humongous (老年代可以是 humongous,可以看出,他可以跨越多個連續regions。直接分配到老年代,防止反復拷貝移動)
Java 9 以后開啟的參數
自從 Java9 后,引入的統一的日志,也就是 Xlog 參數。下面是建議的 GCLog 參數:
-Xlog:gc*:file=your.log:tags,time,uptime,level:filecount=5,filesize=100
G1 的 GC 階段
我們明白,調優的基本步驟就是Measure 收集相關診斷信息 (例如收集詳細的gclog,默認log level info 可以滿足大部分情況)
Understand 理解發生了什么
Tune 調優
只有明白了GC內部發生了什么,才能針對性的對其進行調整。
下面通過一些正常的 GC log 來理解 GC 的三種方式 GC 做了什么。
Young Only Phase
先用張圖來簡單理解 Young GC 過程垃圾回收的過程就是 Allocated->eden; eden -> survivor; survivor -> survivor; survivor -> old;
可以看到,這里有 eden,survivor,old 還有個 free region。
橙色就是活著的對象
G1會把橙色對象拷貝到free region
當拷貝完畢,free region 就會晉升為 survivor region,以前的 eden 就被釋放了
如果 Young gc 中,花費了大量的時間
正常來說,大部分在 Young 的對象都不會存活很長時間
如果不符合這個規則 (大部分在 Young 的對象都不會存活很長時間),你可能需要調整一下 Young 區域占比。來降低 Young 對象的拷貝時間。
-XX:G1NewSizePercent (默認:5) Young region 最小值
-XX:G1MaxNewSizePercent (默認: 60) Young region 最大值
Mixed gc PhaseMixed gc 會選取所有的 Young region + 收益高的若干個 Old region。
同樣的,被回收的 region 就變回 free region 了
從上圖可以了解到 Mixed gc 只能回收部分的老年代
G1 是如何選擇要回收的 regions 的?
-XX:G1MaxNewSizePercent 與 Young 關聯
-XX:MixedGCCountTarget 與 old 關聯
-XX:MixedGCCountTarget默認是8,意味著要在8次以內回收完所有的 old region
換句話說,如果你有 800 個 old region, 那么一次 mixed gc 最大會回收 100 個 old region
G1 也可以被調整成不做這么多工作,也就是回收少點,浪費堆內存,導致更堆使用
-XX:G1MixedGCLiveThresholdPercent(默認:85)可能會提高堆使用率
-XX:G1HeapWastePercent (默認:5) 如果可回收低于這個值, 那么將不會啟動Mixed gc
Full gc PhaseFull gc 是不應該發生的
先來看看 GC 周期
G1 有兩個階段,它會在這兩個階段往返,分別是 Young-only,Space Reclamation.Young-only 包含一系列逐漸填滿 old gen 的 gc
Space Reclamation G1 會遞進地回收 old gen 的空間,同時也處理 Young region
圖是來自 oracle 上對 gc 周期的描述,實心圓都表示一次 GC 停頓藍色 Young-only
黃色 標記過程的停頓
紅色 Mixed gc 停頓
在幾次gc后,old gen 的對象占有比超過了 InitiatingHeapOccupancyPercent,gc就會進入并發標記準備(concurrent mark)。G1 在每一次 Young 回收中都會查找活對象(有引用的對象)
G1 在 old region 并發查找活對象
叫 concurrent marking
可能花費很長時間
不會停止 Java 應用
G1 沒有活對象的引用信息是不能進行垃圾回收的
Mixed gc 依賴 concurrent mark
回到 full gc,從上面簡單分析得出,full gc 發生是沒有足夠的 free region,如果堆是足夠大的,Mixed gc 沒有回收足夠的 old region,或者 concurrent mark 沒法及時完成,都可能會導致 full gc。
gc 日志
[gc,start ] GC(78) Pause Young (Normal) (G1 Evacuation Pause)
上面是連續幾次GC的日志,可以對照著 gc 周期來看。為了方便排版,把時間相關的tag給精簡掉了。GC(78) 是一次普通的young gc,里面信息有各種 region 的變化
這里簡單說一下 humongous 對象的處理
humongous 對象在G1中是被特殊對待的,G1 只決定它們是否生存,回收他們占用的空間,從不會移動它們
Young-Only 階段,humongous regions 可能會被回收
Space-Reclamation,humongous regions 可能會被回收
GC(79) 開始進入并發階段
GC(80) 完成了 Cleanup,緊接著一個 Prepare Mixed GC(81) 的垃圾收集,對應周期虛線右邊的藍實心圓
GC(82) 之后就是 Space Reclamation 階段了,多個 Mixed GC 會進行
根據日志,可以簡單看到每個步驟花費的時間,以及對應區域垃圾的回收情況,結合GC參數,可以定位出什么問題,針對性的調整參數。吞吐量跟低延時是無法兼得的,低延時意味著GC工作會更加頻繁,相對的,會占用應用的資源,吞吐量降低。需要大吞吐量,那么GC工作就會減少,相對的,每次回收的垃圾就會多,暫停時間就會增加,延時就會增加。-XX:MaxGCPauseMillis G1 會盡量滿足這個參數設定的目標時間,通過此參數可以平衡應用需要的吞吐量以及延時。
最后
本文主要參考資料是官方的文章和文檔,沒涉及到復雜的內部實現,新版的JDK除了對G1進行了改良之外,還推出了幾種新的。Epsilon GC (no-op),無操作垃圾回收器,簡單點就是不回收垃圾,等堆空間分配完了,jvm也就停止了
zgc 超大堆垃圾回收器,暫停不超過10ms,支持T級別的堆
Shenandoah 同樣也是低延遲垃圾回收器
由于知識簡陋,難免會有勘誤,歡迎討論。
參考資料
總結
以上是生活随笔為你收集整理的java中的g1_G1GC 概念与性能调优的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 免费PPT模板简历模板下载网址
- 下一篇: 2021年中国LED驱动器(LED照明驱