G1回收器的工作机制G1Garbage First是JVM中一款里程碑式的垃圾回收器它在Java 9成为默认GC。它的设计目标是在可控的停顿时间内尽可能高地实现吞吐量同时避免CMS的碎片问题和传统分代GC的大停顿。一、G1的核心设计思想G1与传统分代GC最大的区别是不再物理划分新生代和老年代而是将整个堆划分为多个大小相等的Region。1. Region化堆内存传统分代堆 ---------------------------------------------------- | 新生代 | 老年代 | | Eden | S0 | S1 | | ---------------------------------------------------- G1堆逻辑上仍分代但物理上混合 ------------------------------------ | E | O | S | H | E | O | O | E | F | ------------------------------------ | O | E | S | H | O | F | E | O | S | ------------------------------------ EEden SSurvivor OOld HHumongous(大对象) FFree(空闲)Region大小通常为1MB-32MB之间2的幂次方通过-XXG1HeapRegionSize设定整个堆通常划分为约2048个Region。逻辑分代G1仍然区分年轻代和老年代但它们是Region的动态集合不是连续的内存块。Humongous Region大小超过Region容量50%的对象存入专门的巨型Region避免移动开销。2. 停顿预测模型G1的独特之处它维护一个停顿预测模型基于历史数据可以预测在某个时间内如200ms能回收多少内存。可控停顿通过-XXMaxGCPauseMillis设置期望最大停顿时间默认200ms。动态调整G1会动态调整年轻代大小、回收策略尽量满足此目标。二、G1的工作阶段G1将GC分为两大类年轻代GC和混合GC。1. 年轻代GCYoung GC触发条件Eden区占满时触发。工作流程标记根对象从GC Roots出发找到存活对象。复制存活对象将Eden和Survivor中的存活对象复制到新的Survivor Region或晋升到Old Region。回收原Region一次性清空原来的Eden和Survivor Region变为空闲状态。特点使用复制算法无碎片。STWStop The World发生但停顿时间通常很短因为存活对象少。完全并发的不多但G1通过多线程并行复制来减少停顿。初始状态 [E] [E] [E] [S] [O] [O] [F] [F] Young GC后 [F] [F] [F] [S] [O] [O] [F] [F] ↑ 新Survivor/晋升2. 并发标记周期Concurrent Marking Cycle这是G1最复杂的部分不产生STW或者极小STW地标记出老年代中的存活对象为后续的混合GC做准备。包含多个子阶段阶段1初始标记Initial Mark- STW标记所有从GC Roots直接可达的对象。借机完成通常在Young GC时顺带完成代价很小。阶段2根区域扫描Root Region Scan扫描Survivor Region中指向老年代的引用。这个阶段是并发执行的不暂停应用线程。阶段3并发标记Concurrent Mark- 并发从GC Roots开始并发地遍历整个堆的对象图标记所有存活对象。这个过程对应用线程影响小但可能产生浮动垃圾标记过程中新产生的垃圾。阶段4最终标记Final Remark- STWSTW处理并发标记阶段遗漏的少量引用变更通过SATB算法确保完整性。相比CMS的最终标记G1的效率更高。阶段5清理Cleanup- STW统计每个Region的存活对象数量和回收价值。不实际回收只是标记哪些Region可以完全回收存活对象为0。根据停顿预测模型按价值高低对Region排序准备混合GC。3. 混合GCMixed GC触发时机并发标记完成后老年代占堆的比例达到阈值-XXInitiatingHeapOccupancyPercent默认45%。核心特点不仅回收年轻代还回收部分老年代Region。工作流程选择Region集合CSet根据停顿预测模型从高价值Region集合中选出本次GC要回收的Region。包括所有年轻代Region部分老年代Region价值最高的那些复制存活对象将CSet中所有Region的存活对象复制到其他空闲Region。这相当于一次全局复制对象可能从年轻代到年轻代、年轻代到老年代、老年代到老年代。回收原Region清空整个CSet释放大量内存。多次执行一次并发标记周期后可能会触发多次混合GC每次回收一部分高价值老年代Region直到老年代内存占用低于阈值。并发标记后按价值排序 Region: O5(价值高) O3(价值高) O8(价值中) O2(价值低) ... 第一次混合GC回收 O5, O3 所有年轻代Region 第二次混合GC回收 O8 当前年轻代Region ...4. Full GC触发条件混合GC无法跟上对象分配速度老年代增长太快。巨型对象分配失败Humongous Region无法找到连续空间。并发标记周期失败。后果最严重的STWG1会退化到Serial Old算法单线程进行全堆标记-整理-压缩。目标通过调优参数尽量避免Full GC发生。三、G1的关键技术点1. SATBSnapshot-At-The-BeginningG1在并发标记开始时会对对象图拍一个逻辑快照。标记过程中即使引用发生变化比如删除了某个引用G1仍然会保留该引用指向的对象为存活。优点避免CMS中复杂的增量更新实现简单。代价可能产生浮动垃圾本应回收但被保留的对象需要后续GC处理。2. Remembered SetRSet每个Region内部维护一个RSet记录哪些Region引用了本Region中的对象。Region A中的对象obj被Region B和Region C引用 Region A的RSet [B, C]作用Young GC时不需要扫描整个堆只需扫描RSet中记录的Region。实现并行化和分代独立回收。维护开销写屏障Write Barrier在引用赋值时更新RSet略有性能损耗。3. 停顿预测模型G1维护一个历史数据库记录每次GC的Region扫描时间对象复制时间更新RSet时间基于这些数据建立一个线性回归模型预测回收N个Region需要的时间从而在制定CSet时做到停顿可控。四、G1 vs CMS vs Parallel GC特性G1CMSParallel GC设计目标可控停顿时间低停顿高吞吐量堆布局Region化连续分代连续分代内存碎片无复制整理有标记-清除无整理停顿时间可预测默认200ms较低较高Full GC很长吞吐量中等较低最高内存开销较高RSet占5%-10%中等低适用场景大堆4GB、响应重要中堆、响应重要高吞吐、可接受停顿选择建议G1堆 4GB期望停顿 1秒Java 9默认。Parallel GC堆 4GB或吞吐优先如批处理。ZGC堆 32GB期望停顿 10msJava 11。五、G1调优示例# 设置期望最大停顿时间G1会尽量满足 -XXMaxGCPauseMillis200 # 设置堆大小和Region大小 -Xmx8g -XXG1HeapRegionSize16m # 触发混合GC的堆占用阈值避免过早/过晚 -XXInitiatingHeapOccupancyPercent45 # 并行线程数 -XXParallelGCThreads8 -XXConcGCThreads2 # 启用G1日志 -Xloggc*fileg1-gc.logtime,level,tags调优方向停顿时间设置不当太短50ms可能频繁GC太长500ms可能失去G1意义。Humongous对象问题大量大对象会直接进入老年代加速Full GC。可以通过调整Region大小或代码优化解决。RSet内存占用G1的RSet可能占堆内存5%-10%避免过多跨Region引用。
G1回收器的工作机制
G1回收器的工作机制G1Garbage First是JVM中一款里程碑式的垃圾回收器它在Java 9成为默认GC。它的设计目标是在可控的停顿时间内尽可能高地实现吞吐量同时避免CMS的碎片问题和传统分代GC的大停顿。一、G1的核心设计思想G1与传统分代GC最大的区别是不再物理划分新生代和老年代而是将整个堆划分为多个大小相等的Region。1. Region化堆内存传统分代堆 ---------------------------------------------------- | 新生代 | 老年代 | | Eden | S0 | S1 | | ---------------------------------------------------- G1堆逻辑上仍分代但物理上混合 ------------------------------------ | E | O | S | H | E | O | O | E | F | ------------------------------------ | O | E | S | H | O | F | E | O | S | ------------------------------------ EEden SSurvivor OOld HHumongous(大对象) FFree(空闲)Region大小通常为1MB-32MB之间2的幂次方通过-XXG1HeapRegionSize设定整个堆通常划分为约2048个Region。逻辑分代G1仍然区分年轻代和老年代但它们是Region的动态集合不是连续的内存块。Humongous Region大小超过Region容量50%的对象存入专门的巨型Region避免移动开销。2. 停顿预测模型G1的独特之处它维护一个停顿预测模型基于历史数据可以预测在某个时间内如200ms能回收多少内存。可控停顿通过-XXMaxGCPauseMillis设置期望最大停顿时间默认200ms。动态调整G1会动态调整年轻代大小、回收策略尽量满足此目标。二、G1的工作阶段G1将GC分为两大类年轻代GC和混合GC。1. 年轻代GCYoung GC触发条件Eden区占满时触发。工作流程标记根对象从GC Roots出发找到存活对象。复制存活对象将Eden和Survivor中的存活对象复制到新的Survivor Region或晋升到Old Region。回收原Region一次性清空原来的Eden和Survivor Region变为空闲状态。特点使用复制算法无碎片。STWStop The World发生但停顿时间通常很短因为存活对象少。完全并发的不多但G1通过多线程并行复制来减少停顿。初始状态 [E] [E] [E] [S] [O] [O] [F] [F] Young GC后 [F] [F] [F] [S] [O] [O] [F] [F] ↑ 新Survivor/晋升2. 并发标记周期Concurrent Marking Cycle这是G1最复杂的部分不产生STW或者极小STW地标记出老年代中的存活对象为后续的混合GC做准备。包含多个子阶段阶段1初始标记Initial Mark- STW标记所有从GC Roots直接可达的对象。借机完成通常在Young GC时顺带完成代价很小。阶段2根区域扫描Root Region Scan扫描Survivor Region中指向老年代的引用。这个阶段是并发执行的不暂停应用线程。阶段3并发标记Concurrent Mark- 并发从GC Roots开始并发地遍历整个堆的对象图标记所有存活对象。这个过程对应用线程影响小但可能产生浮动垃圾标记过程中新产生的垃圾。阶段4最终标记Final Remark- STWSTW处理并发标记阶段遗漏的少量引用变更通过SATB算法确保完整性。相比CMS的最终标记G1的效率更高。阶段5清理Cleanup- STW统计每个Region的存活对象数量和回收价值。不实际回收只是标记哪些Region可以完全回收存活对象为0。根据停顿预测模型按价值高低对Region排序准备混合GC。3. 混合GCMixed GC触发时机并发标记完成后老年代占堆的比例达到阈值-XXInitiatingHeapOccupancyPercent默认45%。核心特点不仅回收年轻代还回收部分老年代Region。工作流程选择Region集合CSet根据停顿预测模型从高价值Region集合中选出本次GC要回收的Region。包括所有年轻代Region部分老年代Region价值最高的那些复制存活对象将CSet中所有Region的存活对象复制到其他空闲Region。这相当于一次全局复制对象可能从年轻代到年轻代、年轻代到老年代、老年代到老年代。回收原Region清空整个CSet释放大量内存。多次执行一次并发标记周期后可能会触发多次混合GC每次回收一部分高价值老年代Region直到老年代内存占用低于阈值。并发标记后按价值排序 Region: O5(价值高) O3(价值高) O8(价值中) O2(价值低) ... 第一次混合GC回收 O5, O3 所有年轻代Region 第二次混合GC回收 O8 当前年轻代Region ...4. Full GC触发条件混合GC无法跟上对象分配速度老年代增长太快。巨型对象分配失败Humongous Region无法找到连续空间。并发标记周期失败。后果最严重的STWG1会退化到Serial Old算法单线程进行全堆标记-整理-压缩。目标通过调优参数尽量避免Full GC发生。三、G1的关键技术点1. SATBSnapshot-At-The-BeginningG1在并发标记开始时会对对象图拍一个逻辑快照。标记过程中即使引用发生变化比如删除了某个引用G1仍然会保留该引用指向的对象为存活。优点避免CMS中复杂的增量更新实现简单。代价可能产生浮动垃圾本应回收但被保留的对象需要后续GC处理。2. Remembered SetRSet每个Region内部维护一个RSet记录哪些Region引用了本Region中的对象。Region A中的对象obj被Region B和Region C引用 Region A的RSet [B, C]作用Young GC时不需要扫描整个堆只需扫描RSet中记录的Region。实现并行化和分代独立回收。维护开销写屏障Write Barrier在引用赋值时更新RSet略有性能损耗。3. 停顿预测模型G1维护一个历史数据库记录每次GC的Region扫描时间对象复制时间更新RSet时间基于这些数据建立一个线性回归模型预测回收N个Region需要的时间从而在制定CSet时做到停顿可控。四、G1 vs CMS vs Parallel GC特性G1CMSParallel GC设计目标可控停顿时间低停顿高吞吐量堆布局Region化连续分代连续分代内存碎片无复制整理有标记-清除无整理停顿时间可预测默认200ms较低较高Full GC很长吞吐量中等较低最高内存开销较高RSet占5%-10%中等低适用场景大堆4GB、响应重要中堆、响应重要高吞吐、可接受停顿选择建议G1堆 4GB期望停顿 1秒Java 9默认。Parallel GC堆 4GB或吞吐优先如批处理。ZGC堆 32GB期望停顿 10msJava 11。五、G1调优示例# 设置期望最大停顿时间G1会尽量满足 -XXMaxGCPauseMillis200 # 设置堆大小和Region大小 -Xmx8g -XXG1HeapRegionSize16m # 触发混合GC的堆占用阈值避免过早/过晚 -XXInitiatingHeapOccupancyPercent45 # 并行线程数 -XXParallelGCThreads8 -XXConcGCThreads2 # 启用G1日志 -Xloggc*fileg1-gc.logtime,level,tags调优方向停顿时间设置不当太短50ms可能频繁GC太长500ms可能失去G1意义。Humongous对象问题大量大对象会直接进入老年代加速Full GC。可以通过调整Region大小或代码优化解决。RSet内存占用G1的RSet可能占堆内存5%-10%避免过多跨Region引用。