标记-整理算法是full gc中老年代内存管理的关键机制,通过移动存活对象归拢内存、消除碎片,确保大对象稳定分配并避免oom。

标记-整理算法在Full GC中不是“可选优化”,而是老年代内存管理的关键机制——它直接决定能否持续稳定分配大对象、避免频繁OOM,尤其在长期运行的Java服务中不可或缺。
为什么Full GC必须用标记-整理
Full GC要回收整个堆(尤其是老年代),而老年代对象存活率高、空间大、碎片敏感。若只用标记-清除:
- 多次回收后产生大量不连续小空闲块,无法容纳新晋升的大对象,触发提前Full GC或直接OOM
- 分配时需遍历空闲链表找合适大小,开销增大且不可预测
- 没有压缩,对象地址长期漂移,不利于内存映射与GC日志分析
标记-整理通过移动存活对象,把已用内存“归拢”到一端,空闲内存形成一块连续区域,从根本上解决碎片问题。
Full GC中标记-整理的实际执行流程
以Serial Old、Parallel Old等传统老年代回收器为例,流程严格分三步,全部发生在Stop-The-World期间:
- 标记阶段:从GC Roots(栈帧变量、静态字段、JNI引用等)出发,遍历可达对象图,为每个存活对象打上标记(如对象头bit位)
- 计算与更新阶段:扫描整个老年代,按顺序为每个存活对象计算其在整理后的新地址,并同步修正所有指向它的引用(包括其他对象字段、栈中局部变量、常量池等)
- 移动与清理阶段:按新地址顺序将存活对象逐个复制/移动过去;移动完成后,原区域整体清空,边界即为新的堆顶
它和年轻代GC的本质区别
年轻代常用复制算法(如ParNew、G1的Eden/Survivor复制),依赖“高死亡率+小空间”,只需拷贝存活对象到另一块空区;而老年代不能简单复制——没有足够备用空间,也不适合频繁拷贝大对象。标记-整理是唯一兼顾碎片治理与空间效率的可行方案。
现代GC中的演进形态
并非所有Full GC都显式执行完整标记-整理:
- G1在Mixed GC中对部分老年代Region做“标记+局部整理”,通过增量方式降低停顿
- ZGC、Shenandoah采用读屏障+并发转移,把移动和引用更新拆到应用线程运行中,大幅缩短STW
- 但底层逻辑未变:识别存活对象 → 重新安置 → 更新引用 → 归还连续空间
无论形式如何变化,消除碎片、保障大对象分配能力,始终是Full GC阶段的核心诉求。











