cms使用标记-清除算法以避免stw时间飙升,接受内存碎片;g1在region粒度上采用标记-复制(标记-整理变种)实现局部整理,兼顾低延迟与无碎片。

标记-整理算法其实并不用于 CMS,CMS 用的是标记-清除算法;而 G1 才真正应用了标记-整理(在 Region 级别结合标记-复制)来避免内存碎片。
CMS 没有采用标记-整理算法
CMS 的设计目标是极短停顿,它选择标记-清除而非标记-整理,是因为老年代通常很大,若在每次回收中移动大量存活对象,会导致 STW 时间飙升——这与“低延迟”初衷相悖。所以 CMS 放弃压缩,接受内存碎片作为代价。
虽然 CMS 提供了 -XX:+UseCMSCompactAtFullCollection 参数支持 Full GC 后压缩,但这属于事后补救,且会引发长时间停顿,日常运行中基本不用。
G1 在 Region 粒度上实现标记-整理
G1 不是对整个老年代做统一整理,而是把堆划分为多个固定大小的 Region,回收时只针对选定的一组 Region 进行:
- 对选中的 Region,先标记存活对象
- 再将它们复制或移动到其他 Region(本质是标记-复制,属标记-整理的变种)
- 原 Region 整块释放,无碎片
这种“局部整理”既控制了单次停顿时间,又从根本上消除了碎片问题。大对象还会被分配到 Humongous Region,避免干扰常规回收节奏。
算法差异带来的实际影响
标记-清除(CMS)和标记-整理(G1)的选择,直接反映在运行表现上:
- CMS 长期运行后,老年代容易出现大量不连续空闲空间,导致 Promotion Failure 或 Concurrent Mode Failure
- G1 能稳定维持可用内存的连续性,更适合堆大于 4GB、存活对象比例高的场景
- G1 的整理动作由回收计划驱动(比如按成本排序 Region),不是每次都全量整理,更可控
为什么 G1 能用整理而 CMS 不能
关键在于粒度与调度机制:
- CMS 面向整块老年代,整理需遍历并移动所有存活对象,停顿不可控
- G1 把整理任务拆解到小 Region 上,每次只处理部分区域,配合预测模型控制停顿
- G1 的 Remembered Set 支持跨 Region 引用追踪,让局部整理不破坏对象图一致性











