跳到主要内容
约 7 分钟3 张卡

Serial、Parallel 与 CMS

Serial、Parallel 与 CMS 是分别侧重低开销、吞吐和短停顿的垃圾收集器。本文先比较它们怎样执行回收,再说明 CMS 为什么需要空闲空间,以及并发失败如何带来长停顿。CMS 以 JDK 8 的历史实现为背景,它已在 JDK 14 移除。

1. 面试核心​

先记住这几条,再读正文
  • Serial。 Serial 使用单个 GC 线程完成主要回收工作,期间暂停应用。
  • Parallel。 Parallel 使用多个 GC 线程并行回收,以吞吐为主要目标。卡 · 三者的比较
  • CMS 停顿阶段。 JDK 8 CMS 的初始标记和重新标记会暂停应用。卡 · CMS
  • 碎片与浮动垃圾。 CMS 正常并发周期采用标记清除,留下的空闲块会形成碎片,标记后才不可达的对象会成为浮动垃圾。
  • 并发回收失败。 CMS 来不及回收或空闲块无法满足分配时,会发生 concurrent mode failure。卡 · 并发模式失败

2. Serial​

Serial 用单个 GC 线程完成主要回收工作,期间暂停应用线程。这种暂停称为 Stop-The-World(STW),可用以下参数选择 Serial:

java -XX:+UseSerialGC -jar app.jar

单线程省去了多个 GC 线程之间的协调成本,所以适合小堆、单核或 CPU 配额很少的简单程序。这类程序也更容易受益于较低的收集器自身开销。

Serial 的年轻代采用复制,老年代采用标记整理,也就是移动存活对象以形成连续空闲空间。存活工作集指回收后仍然存活的对象集合。它越大,单线程需要处理的对象越多,应用等待回收结束的时间就越长。

3. Parallel​

Parallel 让多个 GC 线程同时完成回收,以提高应用在总运行时间中的占比。吞吐优先的任务可以用以下参数选择它:

java -XX:+UseParallelGC -jar batch-job.jar

Parallel 的主要回收工作仍在 STW 中完成。多个 GC 线程分担工作,可以缩短一次回收实际经过的时间,但应用仍需集中暂停。批处理和离线计算更关注单位时间完成的任务量,因此更容易接受这种取舍。

这里的吞吐目标可表示为 应用时间 / (应用时间 + GC 时间)。增加 GC 线程的收益受以下资源限制影响:

  • CPU 配额限制同时能运行多少线程,GC 还会与同机其他应用争抢 CPU。
  • 扫描和复制对象需要内存带宽,带宽饱和后增加线程的收益会降低。
  • NUMA 机器访问远端内存的成本更高。NUMA 指不同处理器访问各内存区域的速度不同。
  • 多线程分配任务和合并结果需要协调,线程越多也会增加这部分开销。

-XX:MaxGCPauseMillis 设置期望的停顿时间,-XX:GCTimeRatio=N 设置 GC 时间占比目标 1/(N+1)。比如,N 为 99 时,目标是把 GC 时间控制在总时间的 1%。收集器会围绕目标调整,但实际能否达到仍取决于负载和可用资源。

4. CMS​

CMS 的全称是 Concurrent Mark Sweep,即并发标记清除。JDK 8 的 CMS 主要回收老年代,年轻代配合 ParNew 回收。它把大部分标记和清除放在应用运行期间完成,以缩短老年代回收的暂停。

理解 CMS,需要区分以下四个主要阶段:

主要阶段应用线程工作
初始标记暂停标记从根和年轻代直接可达的老年代对象
并发标记运行遍历可达对象图
重新标记暂停处理并发期间的引用变化,完成标记
并发清除运行回收已判定不可达的老年代空间

应用在并发标记时仍会修改对象引用。重新标记需要补上这些变化,因此要再次暂停应用,完成存活对象的标记。实际日志还包含预清理和重置等阶段。

并发线程会占用 CPU,使业务能用于计算的资源减少。所以,CMS 用更多并发开销换取较短暂停,应用吞吐也会受到影响。

4.1 碎片与浮动垃圾​

CMS 的碎片与浮动垃圾来自不同原因,需要分别判断。正常标记清除会回收不可达对象,但保留存活对象的位置,所以清除后会留下分散的空闲块。大对象需要合适大小的连续空间,即使总空闲量足够,也会因找不到合适块而分配失败。

浮动垃圾则是已标记为存活、之后才变成不可达的对象。本轮依据已有标记保留它们,下轮再识别并回收。因此,碎片影响空闲空间能否使用,浮动垃圾影响垃圾何时被回收。

4.2 并发模式失败​

并发回收需要时间,CMS 必须在老年代空间耗尽前完成回收。应用在这段时间仍会分配对象,年轻代对象也会晋升,也就是进入老年代。

如果老年代先被占满,或空闲块无法满足分配,就会发生 concurrent mode failure,称为并发模式失败。CMS 随后暂停应用,转入停顿中的回收路径,因此会出现更长的暂停。

分析失败原因时,需要区分以下空间供给压力:

  • 周期启动太晚,剩余空间不足以支撑整个回收周期。
  • 分配或晋升过快,老年代空间比预计更早用完。
  • 存活工作集过大,回收后能腾出的空间有限。
  • 碎片严重,总空闲量足够却缺少合适大小的空闲块。

所以,日志中的老年代占用、空闲块分布和并发周期时长需要放在一起看。

5. CMS 的移除​

CMS 在 JDK 9 弃用,在 JDK 14 移除。因此,Java 17、21 已无法用 -XX:+UseConcMarkSweepGC 选择它。

迁移旧服务时,应清理 CMS 和 ParNew 等旧收集器的专用参数。永久代参数、分代比例也要按目标 JDK 重新核对。可以先用 G1 的默认参数建立基线,观察堆占用、暂停分布和吞吐,再按目标调整或比较其他收集器。

G1 的参数与区域机制见 G1。

6. 三者的比较​

三者的区别在于谁执行回收,以及应用是否同时运行。下表把收益和代价放在一起比较:

收集器回收方式主要收益主要代价
Serial单线程 STW协调成本低大工作集停顿长
Parallel多线程 STW吞吐仍有集中停顿
CMS老年代并发标记清除缩短老年代停顿CPU、碎片和空间余量

并行描述多个 GC 线程同时工作。并发描述 GC 与应用同时运行。CMS 也保留 STW 阶段,两种概念可以出现在同一收集器中。

7. 收集器选择​

选择收集器时,先把业务目标转换成可测量的指标。可以依次检查以下选择依据:

  1. 业务是批处理还是在线请求,主要追求吞吐还是低延迟。
  2. 可接受的 P99、P999 暂停和端到端请求延迟是多少。它们分别表示 99%、99.9% 的观测值低于该值。
  3. 堆大小、存活工作集和分配率是多少。分配率表示单位时间新分配的对象占用多少空间。
  4. 容器有多少 CPU 配额,堆外内存还剩多少余量。
  5. 目标 JDK 与发行版实际支持哪些收集器。
  6. 在同一负载下运行完整的稳定周期,对比吞吐、暂停分布、CPU 和进程内存。

默认收集器可以作为比较起点,是否合适仍需实测。GC 暂停只是请求端到端延迟的一部分,单次回收用时无法说明完整业务效果。

低延迟方案见 低延迟垃圾收集器。

8. 常见问题​

读收集器名称和日志时,要把线程并行、应用暂停与空闲空间分开判断。

8.1 Parallel 的应用暂停​

Parallel 的多个 GC 线程同时工作,但主要回收阶段仍暂停应用线程。这里的“并行”描述 GC 线程之间的关系;应用与 GC 同时运行才称为“并发”。

8.2 CMS 的连续空间需求​

8.3 旧系统的 CMS 知识​

9 · 面试题卡片​

9.1 Serial、Parallel 和 CMS 的目标有什么区别​

出现公司:阿里云、阿里巴巴

考察重点:区分并行和并发,说明三种收集器怎样在吞吐、停顿、CPU 与内存成本之间取舍。

相关内容:三者的比较。

参考回答

Serial 侧重低协调开销,Parallel 侧重吞吐,CMS 侧重缩短老年代回收的停顿。

Serial 在 STW 中用单线程回收,适合小堆和有限 CPU。Parallel 同样暂停应用,但用多个 GC 线程分担工作,以减少回收占用的总时间。CMS 则将老年代的大部分标记和清除与应用并发执行,代价是 CPU 竞争、额外空间余量和碎片。

CMS 已在 JDK 14 移除,迁移到 Java 17、21 时,需要为 G1 等目标收集器重新建立压测基线。

9.2 为什么 CMS 可能发生 concurrent mode failure​

出现公司:阿里巴巴

考察重点:解释并发期间的分配和晋升怎样消耗老年代空间,以及启动时机、碎片与失败停顿的关系。

相关内容:并发模式失败。

参考回答

CMS 在并发周期结束前无法满足老年代分配,就会发生 concurrent mode failure。

应用在回收期间仍会分配对象,并把年轻代对象晋升到老年代。如果周期启动太晚、晋升太快或存活工作集过大,空闲空间就会提前耗尽。碎片也会让大对象找不到合适的空闲块。

这时 CMS 会暂停应用,完成回收,所以失败带来的停顿明显变长。排查需要同时比较老年代占用、分配和晋升速度,以及并发周期时长。

9.3 CMS 哪些阶段会暂停应用,碎片与浮动垃圾有何区别?​

出现公司:暂无已核验的公开来源(本站自测)

考察重点:说明初始标记与重新标记为什么需要暂停,并区分碎片和浮动垃圾的成因及影响。

相关内容:CMS、碎片与浮动垃圾。

参考回答

JDK 8 CMS 的初始标记和重新标记会暂停应用,并发标记与清除则让应用继续运行。

初始标记确定直接可达的老年代对象,重新标记补上并发期间的引用变化。正常清除保留存活对象的位置,回收后的空洞形成碎片,影响大对象分配。浮动垃圾则在标记后才变为不可达,本轮仍被保留,留到后续周期回收。两者分别影响空间布局与回收时机。

10. 参考资料​