1. JVM介紹和運行流程-CSDN博客
2. 什么是程序計數器-CSDN博客
3. java 堆和 JVM 內存結構-CSDN博客
4. 虛擬機棧-CSDN博客
5. JVM 的方法區-CSDN博客
6. JVM直接內存-CSDN博客
7. JVM類加載器與雙親委派模型-CSDN博客
8. JVM類裝載的執行過程-CSDN博客
9. JVM垃圾回收-CSDN博客
10. 垃圾回收的算法-CSDN博客
11. JVM中的分代回收-CSDN博客
12. JVM的垃圾回收器-CSDN博客
13. G1垃圾回收器-CSDN博客
14. 垃圾回收的引用區別-CSDN博客
15. JVM調優的參數設置-CSDN博客
16. JVM調優工具-CSDN博客
1. G1垃圾回收器
G1(Garbage-First)垃圾回收器是Java HotSpot虛擬機中一種面向服務端應用的垃圾回收器,于JDK 7中首次推出,并在JDK 9及以后成為默認的垃圾回收器。
內存布局
-
區域劃分:
-
堆被劃分為多個大小相等的Region(默認約2048個)
-
每個Region可以是Eden、Survivor或Old區
-
還有一種特殊的Humongous區用于存儲大對象(大小超過Region 50%的對象)
-
-
分代管理:
-
仍然保留分代概念,但物理上不再連續
-
年輕代:一組Region(Eden+Survivor)
-
老年代:另一組Region
-
2. G1的三個核心階段
2.1 年輕代回收(Young GC) —— 一階段
特點:
-
STW(Stop-The-World):完全暫停應用線程
-
觸發條件:Eden區填滿時自動觸發
-
目標:快速回收年輕代(Eden + Survivor區)
工作流程:
-
根掃描:標記GC Roots直接引用的對象。
-
存活對象標記:通過可達性分析標記年輕代存活對象。
-
復制/晉升:
-
存活對象被復制到Survivor區(復制算法)
-
達到晉升閾值(
-XX:MaxTenuringThreshold
)的對象晉升到老年代。
-
-
區域清空:回收后的Eden區和部分Survivor區被標記為空閑。
關鍵點:
-
僅處理年輕代Region,耗時短(通常幾毫秒到幾十毫秒)。
-
通過
-XX:G1NewSizePercent
和-XX:G1MaxNewSizePercent
動態調整年輕代大小。
圖示過程:
- 初始時,所有區域都處于空閑狀態
- 創建了一些對象,挑出一些空閑區域作為伊甸園區存儲這些對象
- 當伊甸園需要垃圾回收時,挑出一個空閑區域作為幸存區,用復制算法復制存活對象,需要暫停用戶線程
E 表示:Eden 區
S 表示:Survivor 區
- 隨著時間流逝,伊甸園的內存又有不足
- 將伊甸園以及之前幸存區中的存活對象,采用復制算法,復制到新的幸存區,其中較老對象晉升至老年代?
2.2 并發標記周期(Concurrent Marking Cycle)—— 二階段
特點:
-
部分并發:大部分階段與應用線程并發執行
-
觸發條件:老年代占用達到閾值(默認45%,通過
-XX:InitiatingHeapOccupancyPercent
調整) -
目標:全局標記堆中存活對象,確定回收優先級
分階段流程:
-
初始標記(Initial Mark,STW):
-
短暫暫停,標記GC Roots直接關聯的對象。
-
通常與年輕代回收一起執行(借道Young GC)。
-
-
并發標記(Concurrent Mark):
-
與應用線程并發,遍歷整個堆,標記所有可達對象。
-
使用SATB(Snapshot-At-The-Beginning)算法處理并發期間的對象變化。
-
-
最終標記(Remark,STW):
-
處理并發標記期間漏標的對象(通過寫屏障記錄的變化)。
-
引用處理(如清理軟引用/弱引用)。
-
-
清理(Cleanup,STW):
-
統計各Region的存活對象比例,排序回收價值(垃圾最多的優先)。
-
不實際回收內存,但可能回收完全空閑的Region。
-
關鍵點:
-
并發標記周期為后續混合回收提供數據基礎。
-
通過
-XX:ConcGCThreads
可調整并發標記線程數。
圖示過程:
當老年代占用內存超過閾值(默認是45%)后,觸發并發標記,這時無需暫停用戶線程
2.3?混合回收(Mixed GC)—— 三階段
特點:
-
STW:暫停應用線程
-
觸發條件:并發標記周期完成后,老年代Region達到回收閾值
-
目標:同時回收年輕代和部分老年代(選擇垃圾比例高的Region)
工作流程:
-
年輕代回收:與Young GC相同,處理Eden和Survivor區。
-
老年代回收:
-
根據并發標記的結果,選擇垃圾比例最高的老年代Region(Garbage-First策略)。
-
存活對象被復制到其他Region(壓縮算法減少碎片)。
-
-
多次增量回收:
-
可能分多次完成老年代回收,每次回收部分Region以控制停頓時間。
-
關鍵點:
-
通過
-XX:G1MixedGCLiveThresholdPercent
設置Region存活對象閾值(默認85%,存活對象過多則跳過)。 -
通過
-XX:G1MixedGCCountTarget
控制混合回收的批次(默認8次)。
圖示過程:
- 并發標記之后,會有重新標記階段解決漏標問題,此時需要暫停用戶線程。
- 這些都完成后就知道了老年代有哪些存活對象,隨后進入混合收集階段。
- 此時不會對所有老年代區域進行回收,而是根據暫停時間目標優先回收價值高(存活對象少)的區域(這也是 Gabage First 名稱的由來)
?混合收集階段中,參與復制的有 eden、survivor、old
復制完成,內存得到釋放。進入下一輪的新生代回收、并發標記、混合收集
三階段關系圖?
Full GC(后備方案)
異常情況:Full GC
當G1無法滿足回收需求(如并發模式失敗或晉升失敗)時,會退化為單線程的Serial Old GC(Full GC),導致長時間停頓。應通過調整參數(如增加堆大小、降低InitiatingHeapOccupancyPercent
)避免。
3. 問題總結
3.1 三階段總結
G1 通過這三個階段的配合,實現了低延遲與高吞吐的平衡,尤其適合大內存、多核CPU的場景。
階段 | 并發性 | 目標 | 觸發條件 |
---|---|---|---|
年輕代回收 | STW | 快速回收Eden/Survivor | Eden區滿 |
并發標記周期 | 部分并發 | 標記全堆存活對象,確定優先級 | 老年代占用達閾值(默認45%) |
混合回收 | STW | 回收年輕代+高垃圾老年代Region | 并發標記周期完成后 |
3.2 說一下G1垃圾回收?
- 應用于新生代和老年代,在JDK9之后默認使用G1
- 劃分成多個區域,每個區域都可以充當eden,survivor,old,humongous其中 humongous 專為大對象準備
- 采用復制算法
- 響應時間與吞吐量兼顧
- 分成三個階段:年輕代回收(stw)、并發標記周期(重新標記stw)、混合回收
- 如果并發失敗(即回收速度趕不上創建新對象速度),會觸發Full GC