首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

G1 垃圾收集器深度解析:Region 分區、混合收集、SATB 並發標記與調優實戰

     編輯:Java 相關知識

G1 (Garbage First) 作為 JDK 9+ 默認收集器,面向大堆 (4GB-32GB+) 低延遲場景。本文系統剖析 Region 分區架構、Young/Mixed GC 流程、SATB 並發標記、RSet/CTable 記憶集、關鍵調優參數與 Full GC 觸發場景應對。

一、設計目標與核心創新

二、Region 分區架構

堆內存 (連續虛擬地址空間)
┌─────────────────────────────────────────────┐
│ Region 0 │ Region 1 │ Region 2 │ ... Region N │  ← 2048 個大小相等區域 (1-32MB, 2的冪)
├─────────────────────────────────────────────┤
│  邏輯分代 (非物理連續)                        │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐       │
│  │ Eden    │  │Survivor │  │ Old     │  ...  │  ← 每個 Region 標記邏輯代
│  │ Region  │  │ Region  │  │ Region  │       │
│  └─────────┘  └─────────┘  └─────────┘       │
└─────────────────────────────────────────────┘
  • Region 大小:啟動時根據堆大小計算,目標 ~2048 個 Region,-XX:G1HeapRegionSize 可指定
  • Humongous Region:對象 > 50% Region Size 直接分配為巨型對象,佔用連續多個 Region,默認進老年代
  • 可用空間:Free Region 鏈表管理,分配優先從 Free 獲取

三、記憶集:RSet 與 Card Table

3.1 核心問題

Young GC 掃描 Roots 時,老年代 → 新生代引用若全掃描老年代則極慢。需記錄「哪些老年代 Region 引用了新生代 Region」。

3.2 Card Table (卡表)

  • 將 Region 劃分為 512B Card (默認)
  • 字節數組 byte[] cardTable,索引映射 Card,值 0=清潔/1=髒
  • 寫屏障:引用賦值時標記目標 Card 為髒

3.3 RSet (Remembered Set)

  • 每個 Region 維護一個 RSet:Map<Region, Set<CardIndex>>
  • Key:來源 Region 起始地址;Value:該 Region 中髒 Card 索引集合
  • Young GC 時:只需遍歷 RSet 中的 Card,掃描其中引用,避免全老年代掃描

Point-in vs Point-out:G1 採用 Point-in (誰引用我),CMS 採用 Point-out (我引用誰)。Point-in 更適合 Region 眾多場景。

四、Young GC 流程 (STW)

  1. 根掃描:掃描線程棧、JNI Handles、JVMTI 等 GC Roots
  2. 更新 RSet:處理 Dirty Card Queue,更新 RSet
  3. 處理 RSet:遍歷 RSet,掃描老年代→新生代引用,標記存活對象
  4. 對象復制/遷移:存活對象復制到 Survivor/Old Region (復制算法,隱含整理)
  5. 引用處理:軟/弱/虛/終結器引用處理

CSet (Collection Set):本次 GC 目標 Region 集合。Young GC = 所有 Eden + Survivor Region。

五、並發標記與 Mixed GC (核心創新)

5.1 全局並發標記 5 階段

目標傳統收集器痛點G1 解決方案
可預測停頓CMS 停頓不可控、Full GC 災難性目標停頓時間 MaxGCPauseMillis,自適應調整收集集合
大堆支持CMS 碎片導致大堆不可用Region 分區 + 標記整理(局部復制),無碎片
高吞吐Serial/ParNew 單線程/並行但 STW 長多線程並行 + 並發標記 + 增量收集
階段類型核心工作STW?
初始標記STW掃描 GC Roots,標記直接可達對象 (伴隨 Young GC)是
根區域掃描並發掃描初始標記存活 Region 中的老年代引用否
並發標記並發遍歷對象圖,標記所有可達對象 (可被 Young GC 中斷)否
最終標記STW處理 SATB Buffer,修正並發階段變更,多線程並行是
清理STW+並發統計 Region 活度,識別空 Region、混合收集候選 Region,重置 RSet部分

5.2 SATB (Snapshot-At-The-Beginning) 寫屏障


// 伪代碼:寫屏障邏輯
void preWriteBarrier(Object field) {
    if (markingInProgress) {
        Object oldValue = field.get();
        if (oldValue != null && !isMarked(oldValue)) {
            satbQueue.add(oldValue); // 記錄舊引用對象,防止漏標
        }
    }
}
  • 核心思想:並發標記開始時活著的對象「快照」必須存活,即使引用斷開也標記為灰色
  • 三色不變式:強三色不變式 (CMS 增量更新) vs 弱三色不變式 (G1 SATB)
  • 浮動垃圾:並發階段新分配/引用斷開的對象本輪不回收,下輪處理

5.3 Mixed GC

  • 觸發:老年代佔用達到 InitiatingHeapOccupancyPercent (默認 45%)
  • CSet = 所有新生代 Region + 活度最高的若干老年代 Region
  • 目標:在 MaxGCPauseMillis 內完成,優先回收垃圾密度高的 Region

六、對象分配策略

  1. TLAB:線程本地緩衝,Eden 中劃分,無鎖指針碰撞分配
  2. Eden 分配:TLAB 滿或對象過大,直接在 Eden 指針碰撞/空閒列表分配
  3. Humongous 分配:對象 > 50% Region,直接在老年代尋找連續 Region,可能觸發 Full GC

七、關鍵調優參數

參數默認值調優建議
-XX:+UseG1GC-啟用 G1 (JDK 9+ 默認)
-Xmx-設定最大堆,生產建議 8-32GB
-XX:MaxGCPauseMillis200ms核心手柄,業務可接受停頓上限,100-500ms 常見
-XX:G1HeapRegionSize自動1-32MB 2的冪,大堆可調大 (16/32MB) 減少 Region 數
-XX:ParallelGCThreadsCPU核心數STW 工作線程,≤8 核用核心數,>8 用 5/8
-XX:ConcGCThreadsParallelGCThreads/4並發標記線程,可適當增加加速標記
-XX:InitiatingHeapOccupancyPercent45%提前觸發標記可減少 Full GC 風險,調 35-40%
-XX:G1ReservePercent10%預留內存防疏散失敗,增大至 15-20%

禁用參數:-Xmn、-XX:NewRatio、-XX:SurvivorRatio — 固定新生代破壞 G1 自適應。

八、Full GC 觸發場景與應對 (退化為 Serial Old)

場景原因日誌特徵應對策略
併發模式失敗標記未完成老年代已滿concurrent mode failure增大堆、降低 IHOP、增加並發線程
疏散/晉升失敗Survivor/Old 無空間容納存活對象to-space exhausted/overflow增大 ReservePercent、提前標記、增大堆
巨型對象分配失敗找不到連續 RegionHumongous allocation failed避免巨型對象、增大 Region Size、增大堆
元空間不足Metaspace OOMMetadata GC threshold exceeded增大 MaxMetaspaceSize、排查類加載洩漏

九、G1 vs CMS vs ZGC 選型指南

維度CMSG1ZGC
JDK 版本1.4+ (JDK 14 移除)7u4+ (9+ 默認)11+ (15+ 生產就緒)
堆大小適用< 4-6GB4-32GB+8GB - TB 級
停頓目標低延遲 (非確定性)可預測 (目標導向)亞毫秒 (硬實時)
碎片處理標記清除 + Full GC 整理標記整理 (局部復制)染色指針 + 重定位 (無碎片)
CPU 開銷中等較高 (RSet/SATB)高 (讀屏障/染色指針)
遷移建議停止維護,遷移 G1/ZGC主流穩健選擇極低延遲、超大堆首選
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved