Java中的G1垃圾回收器详解
字数 2289 2025-11-11 16:26:56
Java中的G1垃圾回收器详解
一、G1垃圾回收器概述
G1(Garbage-First)是JDK 7 Update 4中正式引入的服务器端垃圾回收器,旨在替代CMS回收器,解决其内存碎片化和停顿时间不可控等问题。G1的设计目标是在延迟可控的情况下获得尽可能高的吞吐量,适用于多核处理器、大内存容量的服务端环境。它的核心思想是将堆内存划分为多个大小相等的独立区域(Region),并跟踪各个区域的垃圾堆积程度,优先回收垃圾最多的区域(Garbage-First名称的由来)。
二、G1的核心设计思想
-
Region化内存布局:
- G1将整个堆划分为2048个左右的等大小区域(Region),每个Region的大小可以是1MB到32MB(必须是2的幂次)。
- 区域类型包括:
- Eden区:存放新创建的对象。
- Survivor区:存放年轻代GC后存活的对象。
- Old区:存放长期存活的对象。
- Humongous区:专门存放大对象(大小超过Region容量50%的对象)。
- 优势:Region是GC过程中每次回收的最小单元,避免了全堆扫描,使得GC停顿时间更可控。
-
分代收集的弱化:
- G1虽然保留了年轻代和老年代的概念,但物理上不再连续,而是由一系列不连续的Region组成。
- 年轻代和老年代的比例不再固定,而是动态调整(默认年轻代占比5%~60%),通过
-XX:G1NewSizePercent和-XX:G1MaxNewSizePercent参数控制。
-
回收策略:化整为零:
- G1的回收过程不再是整代回收,而是每次只回收部分Region(称为"回收集"或Collection Set)。
- 通过计算每个Region的回收价值(回收所需时间与可释放空间的比值),优先回收收益最大的Region。
三、G1的工作流程
-
年轻代GC(Young GC):
- 触发条件:Eden区被占满时。
- 过程:
- 暂停所有应用线程(Stop-The-World)。
- 从根对象(如栈引用、全局变量)开始扫描,标记Eden和Survivor区中存活的对象。
- 将存活对象复制到新的Survivor区或晋升到Old区。
- 清空Eden和已回收的Survivor区。
- 特点:并行执行,使用多线程加速回收。
-
并发标记周期(Concurrent Marking Cycle):
- 触发条件:堆内存使用率达到阈值(默认45%,通过
-XX:InitiatingHeapOccupancyPercent设置)。 - 阶段划分:
- 初始标记(Initial Mark):短暂STW,标记从GC Roots直接可达的对象。
- 根区域扫描(Root Region Scanning):并发扫描Survivor区中引用老年代的对象。
- 并发标记(Concurrent Marking):并发遍历整个堆,标记存活对象。
- 最终标记(Remark):短暂STW,处理并发标记期间漏标的对象(使用SATB算法)。
- 清理(Cleanup):统计各Region存活对象比例,识别完全空闲的Region,准备混合GC。
- 触发条件:堆内存使用率达到阈值(默认45%,通过
-
混合GC(Mixed GC):
- 触发条件:并发标记周期完成后。
- 回收目标:不仅回收年轻代Region,还会选择部分老年代Region(根据回收价值)加入回收集。
- 过程:类似年轻代GC,但回收范围包括年轻代和部分老年代。
- 目标:逐步减少老年代占用,避免Full GC。
四、关键技术与优化
-
SATB(Snapshot-At-The-Beginning)算法:
- 在并发标记开始时,对堆内存存活对象建立快照。
- 期间新分配的对象默认视为存活,避免漏标。
- 通过写前屏障(Write Barrier)记录并发标记期间被修改的引用,在最终标记阶段重新扫描。
-
记忆集(Remembered Set)与卡表(Card Table):
- 每个Region维护一个记忆集,记录其他Region指向本Region的引用。
- 避免全堆扫描,只需扫描记忆集即可确定跨代引用。
- 卡表是记忆集的实现方式,将堆划分为512字节的卡页,通过写屏障维护脏卡页。
-
停顿预测模型:
- G1根据历史的GC数据预测本次回收的停顿时间。
- 通过调整回收集的大小(Region数量),尽量满足用户设定的最大停顿时间(
-XX:MaxGCPauseMillis,默认200ms)。
五、G1的调优参数
-
基础参数:
-XX:+UseG1GC:启用G1回收器。-XX:MaxGCPauseMillis=200:设置最大停顿时间目标。-XX:G1HeapRegionSize=16m:手动指定Region大小。
-
并发标记控制:
-XX:InitiatingHeapOccupancyPercent=45:触发并发标记的老年代占用阈值。
-
并行线程数:
-XX:ParallelGCThreads:设置STW阶段并行线程数(通常为CPU核数)。
六、G1的适用场景与局限性
-
适用场景:
- 堆内存较大(如6GB以上)的应用。
- 要求低延迟(如停顿时间低于500ms)的服务。
- 应对堆内存占用率随时间增长的情况。
-
局限性:
- 内存占用较高(记忆集和卡表需额外空间)。
- 写屏障开销可能影响吞吐量。
- 小堆环境下优势不明显。
七、总结
G1通过Region化布局和回收价值优先策略,实现了可预测的停顿时间与高吞吐量的平衡。其并发标记和混合GC机制有效减少了Full GC的发生,适合现代大内存应用。理解其核心原理和调优方法,有助于在实际生产中合理配置,发挥最大性能。