G1的GC模式详解

230 阅读4分钟

G1的GC模式详解

一、年轻代GC(Young GC)

1. 触发条件

image.png

  • 阈值动态调整:默认初始阈值 70%(XX:GCHeapFreeLimit=70),但 G1 会根据历史 GC 效率自动调整,公式:新阈值 = max(30%, min(85%, 历史平均回收效率 * 安全系数))

2.回收流程

2.1 Young GC 的回收范围

graph LR
    YoungGC回收 --> 必然回收["所有Eden Region"]
    YoungGC回收 --> 必然回收2["所有Survivor Region"]
    
    必然回收 --> 原因1["Eden区对象100%需处理"]
    必然回收2 --> 原因2["Survivor区需年龄计算"]

2.2 回收流程

sequenceDiagram
    YoungGC->>标记: 标记存活对象
    标记->>定位: 确定存活对象位置
    定位->>申请: 请求新Region
    申请->>分配: 分配Survivor/Old Region
    分配->>复制: 复制存活对象
    复制->>更新: 更新引用地址
    更新->>清空: 原Region加入空闲链表

2.3 空间不足场景

graph TD
    空间不足 --> 场景1["无空闲Survivor Region"]
    空间不足 --> 场景2["Old区无晋升空间"]
    
    场景1 --> 影响["Survivor溢出"]
    场景2 --> 影响["晋升失败"]

2.4 空间不足的处理流

flowchart TD
    空间不足 --> 尝试[尝试扩展堆]
    尝试 --> 条件{可扩展?}
    条件 -->|是| 扩展[扩展堆获取新Region]
    条件 -->|否| 触发[触发Full GC]
    
    扩展 --> 成功[分配成功]
    触发 --> 回收[Serial Old全堆压缩]

2.5 young gc的简化阶段

sequenceDiagram
    YoungGC->>初始标记: 借道STW暂停(<1ms)
    初始标记->>复制: 标记直接可达对象
    复制->>转移: 复制存活对象到新Region
    转移->>清理: 原Region加入空闲链表

与Mixed GC关键差异:

  • 无并发标记:Young GC 的标记是 同步完成 的(在STW期间快速扫描)。
  • 无最终标记:无需处理SATB队列(因无并发修改)。
  • 无Region筛选:强制回收所有年轻代Region。
阶段Young GCMixed GC核心差异
初始标记✅ 借道STW快速标记GC Roots✅ 同Young GC(复用STW窗口)实现相同
并发标记❌ 无✅ 与用户线程并行标记全堆存活对象Mixed GC独有,耗时最长
最终标记❌ 无✅ STW处理SATB队列,修正并发遗漏Mixed GC独有,防漏标保障
筛选回收❌ 无✅ 按价值筛选Old Region并复制Mixed GC独有,增量回收核心
复制存活对象✅ 复制所有年轻代存活对象✅ 复制CSet(Young+筛选的Old)目标Region不同

2.6 为什么Young GC不需要并发标记?

年轻代特性

  • 对象生命周期短(95%以上在Young GC死亡),无需复杂标记。
  • Region数量少(仅占堆20-60%),STW标记开销可控(<5ms)。

二、混合GC(Mixed GC)

1.Mixed GC 的触发条件

1.1 老年代占用阈值

  • 当老年代 Region 占用堆内存的比例达到 XX:InitiatingHeapOccupancyPercent(默认 45%)时,触发 全局并发标记周期(Global Concurrent Marking)。
  • 此阈值并非立即触发 Mixed GC,而是启动标记为后续回收做准备。

1.2 空间不足兜底

  • 若 Young GC 后老年代空间仍不足,或分配大对象(Humongous)失败,也可能提前触发 Mixed GC

2.Mixed GC 的四个核心阶段

2.1 初始标记(Initial Mark, STW)

  • 操作
    • 标记所有从 GC Roots 直接可达的对象(如静态变量、线程栈引用等)。
    • 借道一次 Young GC 的 STW 时段完成,避免额外停顿。
  • 耗时:极短(通常 1-10ms)。

2.2 并发标记(Concurrent Marking)

  • 操作
    • 与用户线程并行,递归标记所有存活对象(使用 三色标记法:白→灰→黑)。
    • 通过 SATB(Snapshot-At-The-Beginning)和增量更新 机制解决漏标问题:
  • 耗时:较长(可能被多次 Young GC 中断)。

2.3 最终标记(Final Remark, STW)

  • 操作
    • 处理 SATB 和增量更新,修正并发标记期间的遗漏。
    • 扫描 Remembered Set(RSet) 更新跨 Region 引用。
  • 耗时:中等(10-50ms,取决于引用变更量)。

2.4 清理与回收(Cleanup & Evacuation)

  • 清理(STW)
    • 统计各 Region 的存活对象比例,筛选回收价值高的 Old Region(存活率 ≤85%,由 XX:G1MixedGCLiveThresholdPercent 控制)。
    • 将完全空闲的 Region 直接加入空闲列表。
  • 回收(Evacuation, STW)
    • CSet(回收集合) = 所有 Young Region + 筛选的高价值 Old Region和Humongous Region
    • 使用复制算法将 CSet 中存活对象转移到空闲 Region(Survivor 或 Old)。
    • 若空间不足(无足够空闲 Region),触发 Full GC
    • 低价值的Old Region不会使用复制算法,但会将死亡的对象空间标记为碎片,加入region内部的碎片链表中管理。
    • 低价值的Humongous Region,不会做任何处理,也不回收。因为拷贝大对象太耗性能。

3.Mixed GC 的退化场景(触发 Full GC)

以下情况会导致 Mixed GC 失败并触发 Serial Old GC(Full GC)

3.1 复制阶段空间不足

  • 存活对象复制时无空闲 Region 可用(需调整 XX:G1ReservePercent 预留空间)。

3.2 大对象分配失败

  • Humongous Region 无连续空间存放巨型对象。

3.3 并发标记超时

  • 堆满前未完成标记,被迫 Full GC

三、Full GC

Full GC作为垃圾收集器的最后方案,会触发 长时间 STW 停顿(秒级),主要是通过serial收集器作为最后的回收。

1.触发场景

  • 并发模式失败(Concurrent Mode Failure)
  • 晋升失败(Promotion Failure)
  • 大对象分配失败(Humongous Allocation Failure)
  • 元空间耗尽(Metaspace Exhaustion)