g1通过分区化、复制式整理和价值驱动回收继承标记-整理核心思想,实现可控停顿与碎片控制。它以region为单位选择性整理,标记阶段并发进行并依赖rset定位跨区引用;evacuation阶段将存活对象复制到新region,批量更新引用;避免全局stw压缩,仅在full gc时退化为传统方式。

标记-整理算法在G1中不是直接照搬,而是以“分区化+局部整理”方式实现的变形应用。G1不采用全局压缩,而是按Region粒度选择性整理,兼顾停顿可控与碎片控制。
G1如何继承标记-整理的核心思想
G1保留了标记-整理算法最关键的两个目标:消除内存碎片、避免全堆连续压缩带来的高延迟。它通过以下方式继承本质逻辑:
- 标记阶段一致:同样从GC Roots出发,并发标记存活对象,依赖Remembered Set(RSet)快速定位跨Region引用,确保标记准确性
- 整理即压缩:在筛选回收(Evacuation)阶段,G1将选中的Region中所有存活对象复制到新的空闲Region,原Region整体清空——这等效于“向一端压缩+清除另一端”,只是压缩范围限定在被回收的Region集合内
- 引用更新必做:对象移动后,G1会批量修正RSet和卡片表中对应的引用条目,也同步更新Java线程栈、寄存器等位置的引用,确保对象地址变更不导致逻辑错误
G1对传统标记-整理的关键变形
传统标记-整理作用于整个老年代,而G1将其拆解为可预测、可调度的微操作:
- 区域化整理(Region-based):堆被划分为固定大小(1–32MB)的Region,整理只发生在本次回收计划选定的若干Region中,而非整个老年代
- 复制式整理(Copying Compact):G1不用“就地移动”,而是将存活对象复制到其他Region,天然规避了就地压缩时的读写冲突和复杂指针滑动问题
- 价值驱动回收(Cost-Benefit Sorting):G1统计每个Region的垃圾占比(回收价值)和复制成本,优先整理“高收益低开销”的Region,使有限停顿时间内释放最多空间
- 无全局STW整理:Young GC和Mixed GC都只暂停用户线程短暂时间(毫秒级),真正的全堆整理(Full GC)仅在极端情况下触发,此时才退化为传统标记-整理式全局压缩
为什么G1用这种变形更合适
直接套用传统标记-整理会导致老年代GC停顿不可控,而G1的变形设计直击实际痛点:
- 大堆场景下,一次全局整理可能耗时数百毫秒甚至秒级;G1把压力分散到多次小规模Mixed GC中,保障响应稳定性
- 复制到新Region天然支持并发分配,无需像就地压缩那样同步冻结所有访问,降低同步开销
- Region间独立管理,配合RSet可精准追踪跨区引用,避免传统整理中因引用关系复杂导致的遍历爆炸
- 当出现大对象(Humongous Object)或内存严重碎片化时,G1仍能通过触发Full GC回退到标准标记-整理流程,保留兜底能力
实际影响与调优提示
理解这一变形有助于定位和优化G1行为:
- 若Mixed GC频繁但回收空间少,说明Region筛选策略偏保守——可适当调低-XX:G1MixedGCCountTarget或提高-XX:G1OldCSetRegionThresholdPercent
- 大量Humongous Region堆积,易诱发Full GC——应监控-XX:+PrintGCDetails中Humongous Allocation日志,考虑增大Region大小或优化大对象生命周期
- G1默认不压缩元空间和代码缓存,这些区域仍可能碎片化——需单独关注MetaspaceSize和ReservedCodeCacheSize配置











