3. CMS 垃圾收集器详解:工作原理与核心阶段
CMS(Concurrent Mark Sweep)垃圾收集器以“低停顿”为目标,通过将大部分标记和清理工作与业务线程并发执行,显著减少 GC 引起的应用暂停时间。在数据库迁移场景中,CMS 的行为直接决定了迁移期间 JVM 的响应稳定性。本节深入剖析 CMS 的四个核心阶段及其内部协作机制。
3.1 CMS 工作原理概述
CMS 基于“标记-清除”算法,将 GC 过程拆分为多个阶段,其中耗时最长的并发标记和并发清理阶段与应用线程同时运行。其核心设计思想是:用更长的总 GC 时间换取更短的 STW(Stop-The-World)暂停。
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 最核心的阶段。它从初始标记阶段标记的对象出发,递归遍历整个对象图,标记所有可达的存活对象。这个阶段与业务线程同时运行,因此不会暂停应用。
并发标记的耗时取决于堆中存活对象的数量和对象图的复杂度。在数据库迁移过程中,如果应用创建了大量临时对象或缓存对象,并发标记的耗时可能显著增加。
3.5 阶段三:重新标记 (Remark)
重新标记是 CMS 周期中的第二个 STW 暂停。它的目的是修正并发标记期间因业务线程运行而产生的引用变化。具体来说,重新标记会处理以下两类对象:
- 增量更新记录的对象:在并发标记期间,写屏障记录下所有被修改的引用关系,重新标记阶段会重新扫描这些引用,确保新分配的存活对象被正确标记。
- 新生代晋升的对象:如果并发标记期间发生了 Minor GC,部分对象从新生代晋升到老年代,这些对象也需要在重新标记阶段被重新扫描。
重新标记的暂停时间通常比初始标记长,但比并发标记短得多,一般在几十毫秒到几百毫秒之间。在数据库迁移场景中,如果应用在并发标记期间产生了大量对象引用变更,重新标记的耗时可能增加。
3.6 阶段四:并发清理 (Concurrent Sweep)
并发清理阶段与业务线程同时运行,回收所有被标记为死亡的对象所占用的内存空间。CMS 使用“标记-清除”算法,因此清理后的内存空间可能产生碎片。
并发清理的耗时取决于死亡对象的数量和内存碎片程度。在数据库迁移过程中,如果迁移操作产生了大量短生命周期的大对象,并发清理的负担会加重。
3.7 CMS 工作流程总览
下图展示了 CMS 四个阶段的时间线关系,以及 STW 暂停与并发执行的交替模式。
3.8 CMS 与数据库迁移的关联
在数据库迁移场景中,CMS 的以下特性直接影响迁移过程的稳定性:
- 低停顿优势:迁移过程中,应用需要持续处理数据库请求,CMS 的短 STW 暂停有助于保持连接池不超时、事务不中断。
- 并发标记压力:迁移操作可能产生大量临时对象(如数据转换对象、批量处理结果集),增加并发标记的负担,可能导致标记周期延长。
- 碎片化风险:迁移过程中频繁创建和释放大对象(如批量数据缓存),会加速老年代碎片化,增加并发模式失败的概率。
- 重新标记波动:如果迁移操作在并发标记期间持续修改对象引用(如更新缓存、重建索引),重新标记阶段的暂停时间可能异常增长。
-XX:CMSInitiatingOccupancyFraction 参数提前触发 CMS 周期,避免迁移高峰期发生并发模式失败。同时监控 -XX:+PrintGCDetails 输出的 CMS 各阶段耗时,及时发现异常。