G1垃圾回收器
G1(Garbage First)是现代 HotSpot JVM 中非常重要的垃圾回收器。它的目标是在可控停顿时间下,尽可能获得较好吞吐。
# 1. G1 的设计目标
G1 面向服务端应用,适合较大堆和对延迟有一定要求的场景。
它关注:
- 可预测停顿。
- 大堆管理。
- 分区回收。
- 并发标记。
- 整理内存减少碎片。
JDK 9 起,G1 成为服务端默认垃圾回收器。
# 2. Region
G1 把堆划分为多个大小相等的 Region。
Heap = Region + Region + Region + ...
Region 可以扮演:
- Eden。
- Survivor。
- Old。
- Humongous。
这使 G1 不再依赖物理连续的新生代和老年代。
# 3. Garbage First 的含义
G1 会根据每个 Region 的垃圾比例和回收收益,优先回收“垃圾最多、收益最高”的 Region。
这就是 Garbage First 的含义。
它不是每次回收整个老年代,而是在停顿目标内选择一批 Region 构成 Collection Set。
# 4. G1 回收类型
常见回收类型:
- Young GC:回收年轻代 Region。
- Concurrent Mark:并发标记整个堆的存活信息。
- Mixed GC:回收年轻代 Region,同时回收部分老年代 Region。
- Full GC:退化场景,通常需要重点关注。
# 5. 停顿目标
G1 可以设置期望停顿目标:
-XX:MaxGCPauseMillis=200
这是目标,不是硬保证。JVM 会尽量根据目标选择回收多少 Region。
停顿目标设置过低可能导致:
- 每次回收 Region 太少。
- 垃圾回收追不上分配速度。
- 并发标记压力增加。
- 甚至触发 Full GC。
# 6. Humongous 对象
超过 Region 一半大小的对象会被视为 Humongous 对象。
大对象会占用一个或多个连续 Region,容易带来碎片和回收压力。
如果 GC 日志中 Humongous 对象很多,应检查:
- 大数组。
- 大字符串。
- 大缓存块。
- 一次性读取大文件。
# 7. G1 常用参数
常见参数:
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=45
-XX:G1HeapRegionSize=16m
多数情况下不建议一开始就调太多参数。先观察 GC 日志和业务指标,再决定是否调整。
# 8. 阶段小结
G1 的核心是 Region、可预测停顿、并发标记和优先回收高收益区域。普通服务端应用使用现代 JDK 时,G1 通常是稳妥的默认选择。但 G1 不是万能的,停顿目标、Humongous 对象、分配速度和老年代增长都需要结合日志分析。
# 9. G1 Region 布局图
Heap
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ E │ E │ S │ O │ O │ H │ E │ O │
└────┴────┴────┴────┴────┴────┴────┴────┘
E = Eden Region
S = Survivor Region
O = Old Region
H = Humongous Region
这些 Region 在物理上不需要连续,G1 可以灵活调整年轻代大小,并选择部分老年代 Region 做 Mixed GC。
# 10. G1 并发标记流程
初始标记(STW)
│ 标记 GC Roots 直接可达对象
▼
并发标记(并发)
│ 与应用线程同时执行,扫描对象图
▼
最终标记(STW)
│ 处理并发期间变化的引用
▼
清理(部分 STW)
│ 统计 Region 回收价值
▼
Mixed GC
│ 回收年轻代 + 部分高收益老年代 Region
G1 的停顿控制来自“每次只选择一部分 Region 回收”,而不是每次都回收整个老年代。
# 11. G1 常见日志信号
| 日志信号 | 可能含义 |
|---|---|
G1 Evacuation Pause | 正常转移暂停 |
To-space exhausted | 转移空间不足,风险较高 |
Humongous allocation | 大对象分配 |
Concurrent Mark Cycle | 并发标记周期 |
Full GC | G1 退化或严重内存压力 |
如果 G1 出现 Full GC,要重点分析是不是并发回收追不上分配速度、大对象太多、老年代碎片或参数设置不合理。
# 12. G1 调参原则
优先看:
- 堆是否足够。
- 分配速率是否异常。
- Humongous 对象是否过多。
- 停顿目标是否过低。
- 并发标记是否启动太晚。
常见参数不是越多越好。很多情况下只需要:
-XX:+UseG1GC
-Xms<size>
-Xmx<size>
-Xlog:gc*
MaxGCPauseMillis 是目标,不是硬保证。设置过低可能让 G1 每次回收太少,反而积压垃圾。
# 13. Tips 快问快答
Q:G1 为什么叫 Garbage First?
A:因为它优先回收垃圾比例高、收益大的 Region。
Q:G1 还有新生代和老年代吗?
A:有逻辑上的分代,但物理上通过 Region 承载,不再是连续区域。
Q:G1 适合所有场景吗?
A:不适合所有。极致吞吐批处理可评估 Parallel,极低延迟可评估 ZGC。
Q:G1 出现 Full GC 说明什么?
A:说明 G1 正常并发/混合回收机制可能跟不上,需要重点排查分配速率、大对象、堆大小和参数。