专栏文章
专栏文章
GC 垃圾回收系列
1. GC 系列 #01:GC 总览与历史:自动内存管理的起源与演化 2. GC 系列 #02:GC 基础算法:标记-清除、标记-整理、复制收集、引用计数 3. GC 系列 #03:分代假说与分代收集:朝生夕死的工程哲学 4. GC 系列 #04:CMS 收集器:Java 第一个并发收集器的设计与缺陷 5. GC 系列 #05:G1 收集器:Region 化堆与可预测停顿 6. GC 系列 #06:ZGC 与 Shenandoah:亚毫秒级停顿的并发移动收集器 7. GC 系列 #07:Go 的 GC:并发三色标记与混合写屏障 8. GC 系列 #08:Python 的内存管理:引用计数与分代循环 GC 9. GC 系列 #09:GC 调优实践:JVM 日志解读与 G1/ZGC 参数策略

GC 系列 #04:CMS 收集器:Java 第一个并发收集器的设计与缺陷

发布于 2026-05-25 14:16 👁 20 次阅读
#GC#JVM#理论#CMS

CMS(Concurrent Mark-Sweep)是 Java 第一个真正意义上的并发收集器,它把大部分标记工作放到与应用线程并发执行,大幅缩短了停顿时间。本文分析 CMS 的四个阶段、两大缺陷,以及为何最终被 G1 取代。


目录

章节 说明
设计目标 低延迟优先,牺牲吞吐量
四个阶段 初始标记→并发标记→重新标记→并发清除
两大缺陷 浮动垃圾与内存碎片
并发失败与降级 Concurrent Mode Failure
CMS 的历史地位 过渡性角色

设计目标

在 CMS 之前(Serial Old、Parallel Old),老年代 GC 是完全 STW 的——应用线程全部暂停,GC 线程独占 CPU 扫描整个老年代,停顿时间可达数秒。

CMS 的核心思想: 把耗时最长的标记和清除工作拆分,让大部分工作与应用线程并发执行,只在必要时短暂 STW。

gc cms timeline


四个阶段

阶段一:初始标记(Initial Mark)⏸️ STW

做什么: 标记 GC Roots 直接可达的对象(第一层)

gc cms phase1 initial mark

为什么需要 STW: 扫描线程栈帧、静态变量等 GC Roots 时,如果应用线程同时在运行(方法调用、引用赋值),GC Roots 集合一直在变化,无法获取一致快照,会导致漏标对象。初始标记虽然只扫描第一层,但必须是原子性的。

特点: 停顿极短(毫秒级),因为只扫描 GC Roots 直接引用,不追踪整个对象图。

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

做什么: 从初始标记的对象出发,并发地遍历整个对象图

gc cms phase2 concurrent mark

特点: 耗时最长,但与应用并发,不 STW。问题:应用线程可能在此期间修改引用关系,导致标记不准确(需要第三阶段修正)。

阶段三:重新标记(Remark)⏸️ STW

做什么: 修正并发标记期间因应用线程运行而导致的标记变动,使用增量更新(Incremental Update) 算法

gc cms phase3 remark

为什么需要 STW: 处理脏引用时,如果应用线程同时还在产生新的引用变化,会形成无限追逐——新变化不断写入脏集合,永远无法处理完毕。STW 保证了处理期间不再有新变化,使修正可以在有限时间内完成。

并发标记期间 GC Roots 的变化如何处理:

gc cms concurrent gc roots

特点: STW,比初始标记慢(需要扫描整个年轻代 + 脏对象),是 CMS 停顿最长的阶段,但远比 Full GC 短。

阶段四:并发清除(Concurrent Sweep)🔄 并发

做什么: 并发地清除未标记(垃圾)对象,回收内存

gc cms phase4 concurrent sweep

特点: 使用空闲列表管理回收空间(不整理,不移动对象,避免更新引用的开销),不 STW


两大缺陷

缺陷一:浮动垃圾(Floating Garbage)

并发标记和并发清除期间,应用线程仍在运行,可能产生新的垃圾:

gc cms floating garbage

-XX:CMSInitiatingOccupancyFraction=68  # 可调低触发阈值,默认 92%

缺陷二:内存碎片

CMS 使用标记-清除(不是标记-整理),清除后不移动对象,产生大量碎片:

gc cms fragmentation


并发失败与降级

Concurrent Mode Failure: CMS 并发收集期间,老年代已经被填满,来不及完成 GC。

原因:

  1. 老年代填满速度过快(大量对象晋升)
  2. 浮动垃圾积累
  3. -XX:CMSInitiatingOccupancyFraction 设置过高

后果:

这是 CMS 最严重的问题,在高负载下难以避免。


CMS 的历史地位

CMS 在 JDK 5 引入,JDK 9 被标记为废弃,JDK 14 被彻底移除。

贡献:

局限:

G1 的设计目标正是解决 CMS 的这些问题:通过 Region 化堆布局同时做到低延迟和可预测停顿。

CMS 适用场景(历史参考)

  • 老年代大,Full GC 代价高
  • 延迟敏感(互联网服务、实时系统)
  • JDK 7/8 时代,G1 还不成熟时的最优选

参考资料

  • 《深入理解 Java 虚拟机》第 3 章 — 周志明
  • JEP 291: Deprecate the Concurrent Mark Sweep (CMS) GC
  • G1 收集器(CMS 的继任者)
← 返回列表

评论 (0)

暂无评论,来留下第一条吧。

发表评论