标记-整理算法通过移动存活对象至内存一端并紧凑排列,彻底消除内存碎片;其核心是“整理”而非仅清除,使空闲空间天然连续,适合老年代高存活率场景。

标记整理算法通过移动存活对象并紧凑排列,从根源上消除内存碎片——它不只“清理”,而是“重排+清边”,让剩余空间变成一块连续可用区域。
标记整理如何实现零碎片
关键在于“整理”这个动作:不是简单删掉垃圾,而是把所有活对象统一搬到内存起始端,按地址顺序挨个摆放。搬完后,直接把边界之后的整片区域一次性清空。这样剩下的空闲空间天然就是连续的,大对象分配时再也不用担心“有空间但不连着”。
为什么比标记清除更彻底
- 标记清除只是删掉被标记的对象,留下散落的空洞,后续分配容易卡在“有总空间但没连续块”上
- 标记整理强制压缩,所有存活对象紧贴排列,空闲区自动合并成单一大块
- 不需要额外维护空闲链表或查找最佳适配块,分配时只需移动一个指针即可
它适合老年代的根本原因
老年代对象存活率高,复制算法搬动成本太大,而标记清除又撑不住长期运行后的碎片压力。标记整理在二者间折中:不浪费50%空间,也不容忍碎片累积——哪怕一次GC只回收10%对象,整理后依然能保证后续大对象(比如缓存、大数组)顺利分配。
实际效果取决于整理策略
不同收集器实现略有差异:
立即学习“Java免费学习笔记(深入)”;
- Serial Old 和 CMS 的初始版本使用“滑动压缩”,从低地址开始逐个移动对象
- G1 和 ZGC 不采用传统标记整理,但通过 Region 划分+局部整理,达到等效的碎片控制效果
- Shenandoah 在并发阶段完成对象移动,大幅缩短 Stop-The-World 时间,但整理逻辑本质一致


















