3. CMS 垃圾收集器详解:工作原理与核心阶段

CMS(Concurrent Mark Sweep)垃圾收集器以“低停顿”为目标,通过将大部分标记和清理工作与业务线程并发执行,显著减少 GC 引起的应用暂停时间。在数据库迁移场景中,CMS 的行为直接决定了迁移期间 JVM 的响应稳定性。本节深入剖析 CMS 的四个核心阶段及其内部协作机制。

3.1 CMS 工作原理概述

CMS 基于“标记-清除”算法,将 GC 过程拆分为多个阶段,其中耗时最长的并发标记和并发清理阶段与应用线程同时运行。其核心设计思想是:用更长的总 GC 时间换取更短的 STW(Stop-The-World)暂停。

适用场景:CMS 适用于对延迟敏感、对吞吐量要求相对宽松的应用,如 Web 服务、实时交易系统、数据库中间件等。在数据库迁移过程中,CMS 的低停顿特性有助于保持连接池和事务处理的连续性。

3.2 CMS 四个核心阶段详解

CMS 的完整工作周期分为以下四个阶段,其中阶段 1 和阶段 3 需要暂停应用线程(STW),阶段 2 和阶段 4 与业务线程并发执行。

阶段 名称 是否 STW 主要工作 耗时特征
1 初始标记 (Initial Mark) 是 标记 GC Roots 直接引用的对象 极短(毫秒级)
2 并发标记 (Concurrent Mark) 否 从 GC Roots 出发,遍历整个对象图 较长(秒级)
3 重新标记 (Remark) 是 修正并发标记期间因业务线程运行产生的引用变化 中等(几十毫秒)
4 并发清理 (Concurrent Sweep) 否 回收被标记为死亡的对象所占用的内存空间 较长(秒级)

3.3 阶段一:初始标记 (Initial Mark)

初始标记是 CMS 周期中第一个 STW 暂停。它的任务非常明确:标记所有从 GC Roots 直接可达的存活对象。GC Roots 包括:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中 JNI(Native 方法)引用的对象
  • 活跃线程(Thread 对象)

由于只扫描 GC Roots 的直接引用,不深入遍历对象图,初始标记的暂停时间非常短,通常在几毫秒到十几毫秒之间。在数据库迁移场景中,这个阶段对应用的影响几乎可以忽略。

3.4 阶段二:并发标记 (Concurrent Mark)

并发标记是 CMS 最核心的阶段。它从初始标记阶段标记的对象出发,递归遍历整个对象图,标记所有可达的存活对象。这个阶段与业务线程同时运行,因此不会暂停应用。

并发标记的挑战:由于业务线程在并发标记期间持续运行,对象引用关系可能随时发生变化。CMS 通过“写屏障 + 增量更新”机制来跟踪这些变化,确保不会漏标存活对象。

并发标记的耗时取决于堆中存活对象的数量和对象图的复杂度。在数据库迁移过程中,如果应用创建了大量临时对象或缓存对象,并发标记的耗时可能显著增加。

3.5 阶段三:重新标记 (Remark)

重新标记是 CMS 周期中的第二个 STW 暂停。它的目的是修正并发标记期间因业务线程运行而产生的引用变化。具体来说,重新标记会处理以下两类对象:

  1. 增量更新记录的对象:在并发标记期间,写屏障记录下所有被修改的引用关系,重新标记阶段会重新扫描这些引用,确保新分配的存活对象被正确标记。
  2. 新生代晋升的对象:如果并发标记期间发生了 Minor GC,部分对象从新生代晋升到老年代,这些对象也需要在重新标记阶段被重新扫描。

重新标记的暂停时间通常比初始标记长,但比并发标记短得多,一般在几十毫秒到几百毫秒之间。在数据库迁移场景中,如果应用在并发标记期间产生了大量对象引用变更,重新标记的耗时可能增加。

3.6 阶段四:并发清理 (Concurrent Sweep)

并发清理阶段与业务线程同时运行,回收所有被标记为死亡的对象所占用的内存空间。CMS 使用“标记-清除”算法,因此清理后的内存空间可能产生碎片。

内存碎片问题:CMS 不进行内存压缩,长期运行后老年代会产生大量内存碎片。当碎片化严重时,即使老年代总空闲空间足够,也无法为大对象分配连续内存,导致“并发模式失败”(Concurrent Mode Failure),触发 Serial Old 作为后备收集器,造成长时间的 STW 暂停。

并发清理的耗时取决于死亡对象的数量和内存碎片程度。在数据库迁移过程中,如果迁移操作产生了大量短生命周期的大对象,并发清理的负担会加重。

3.7 CMS 工作流程总览

下图展示了 CMS 四个阶段的时间线关系,以及 STW 暂停与并发执行的交替模式。

CMS 垃圾收集器工作流程时间线 初始标记 STW 并发标记 并发 重新标记 STW 并发清理 并发 应用线程状态: 暂停 运行 暂停 运行 关键说明: • 红色阶段(初始标记、重新标记)需要暂停应用线程,但暂停时间较短。 • 蓝色/绿色阶段(并发标记、并发清理)与应用线程同时运行,不暂停业务。

3.8 CMS 与数据库迁移的关联

在数据库迁移场景中,CMS 的以下特性直接影响迁移过程的稳定性:

  • 低停顿优势:迁移过程中,应用需要持续处理数据库请求,CMS 的短 STW 暂停有助于保持连接池不超时、事务不中断。
  • 并发标记压力:迁移操作可能产生大量临时对象(如数据转换对象、批量处理结果集),增加并发标记的负担,可能导致标记周期延长。
  • 碎片化风险:迁移过程中频繁创建和释放大对象(如批量数据缓存),会加速老年代碎片化,增加并发模式失败的概率。
  • 重新标记波动:如果迁移操作在并发标记期间持续修改对象引用(如更新缓存、重建索引),重新标记阶段的暂停时间可能异常增长。
调优方向:在数据库迁移前,建议通过 -XX:CMSInitiatingOccupancyFraction 参数提前触发 CMS 周期,避免迁移高峰期发生并发模式失败。同时监控 -XX:+PrintGCDetails 输出的 CMS 各阶段耗时,及时发现异常。