CMS通过并发标记与清除大幅降低STW时间:初始标记和重新标记需短暂暂停,仅处理GC Roots直接关联对象及并发变动修正;而耗时最长的标记和清除阶段与用户线程并行执行,使90%以上标记工作在应用运行中完成,总停顿远低于串行收集器。

CMS(Concurrent Mark-Sweep)收集器通过将原本需要“Stop-The-World”的标记和清除阶段尽可能移到并发执行,显著减少 GC 停顿时间。它的核心思路不是避免暂停,而是把最耗时的两个阶段——标记存活对象和清理已死对象——与用户线程同时运行。
并发标记阶段如何降低 STW 时间
在 CMS 中,“初始标记”仍需短暂暂停(仅标记 GC Roots 直接关联的对象),但紧随其后的“并发标记”阶段完全与用户线程并行:JVM 从 GC Roots 出发,一边追踪引用链,一边允许应用继续分配和修改对象。这避免了传统 Serial 或 Parallel 收集器中完整遍历整个堆时的长停顿。
- 初始标记(Initial Mark):STW,极短,只扫描 GC Roots 直接引用
- 并发标记(Concurrent Mark):与用户线程并发执行,不暂停应用
- 重新标记(Remark):STW,修正并发期间因对象引用变化导致的漏标,通常比纯串行标记快得多
为什么并发标记能大幅缩短总停顿
堆越大,存活对象越多,标记耗时越长。CMS 把这部分工作分摊到应用运行过程中完成,使 STW 阶段只剩下轻量级操作。例如一个 4GB 老年代,在并发标记下,90% 以上的标记工作发生在应用运行时;而重新标记阶段只需处理少量“浮动垃圾”和“并发更新”,耗时通常控制在几十毫秒内。
- 初始标记 + 重新标记 的总 STW 时间远小于一次完整串行标记
- 并发标记期间用户线程照常运行,吞吐不受影响
- 即使并发标记耗时较长(如几百毫秒),也不表现为“卡顿”
需要注意的副作用和调优点
并发执行带来便利,也引入新问题:用户线程修改引用可能导致标记结果不准,因此需要写屏障(Write Barrier)记录变动,并在重新标记阶段补救。这也意味着 CMS 对 CPU 资源更敏感。
立即学习“Java免费学习笔记(深入)”;
- 必须预留足够内存空间,避免并发标记未完成就发生并发失败(Concurrent Mode Failure)
- 启用 -XX:+UseConcMarkSweepGC 后建议搭配 -XX:CMSInitiatingOccupancyFraction 提前触发 CMS 周期
- 若应用写入频繁、老年代增长快,可调低触发阈值(如设为 70),防止退化为 Full GC


















