面试知识库
进阶

经典垃圾收集器与组合#

一句话答案#

HotSpot 的收集器分新生代和老年代两类:新生代有 Serial(单线程)、ParNew(多线程,CMS 搭档)、Parallel Scavenge(吞吐量优先);老年代有 Serial Old、Parallel Old(吞吐量优先)、CMS(低停顿);G1 之后是面向整堆的 Region 收集器。选型核心是在「吞吐量」和「停顿时间」之间权衡:Parallel 系列追吞吐,CMS/G1/ZGC 追低停顿。

核心要点

1. 收集器按代划分(连线表示可搭配组合):

        新生代                    老年代
   ┌──────────────┐         ┌──────────────┐
   │ Serial       │────────▶│ Serial Old   │   客户端/小堆,单线程,STW
   │ ParNew       │────────▶│ CMS          │   低停顿经典组合
   │ Parallel     │────────▶│ Parallel Old │   吞吐量优先(JDK8 默认)
   │ Scavenge     │         │              │
   └──────────────┘         └──────────────┘
            G1 / ZGC / Shenandoah:不分代连线,面向整堆 Region
plaintext

2. 各收集器一句话:

收集器区域线程算法目标关键点
Serial新生代单线程复制最简单高效(无线程切换开销),客户端模式默认
ParNew新生代多线程复制低停顿Serial 的多线程版,唯一能和 CMS 搭配的新生代收集器
Parallel Scavenge新生代多线程复制吞吐量可控吞吐量(GC 时间占比),有自适应调节 -XX:+UseAdaptiveSizePolicy
Serial Old老年代单线程标记-整理CMS 失败时的后备方案
Parallel Old老年代多线程标记-整理吞吐量与 Parallel Scavenge 搭配,JDK8 默认组合
CMS老年代多线程并发标记-清除低停顿详见 CMS收集器,有碎片+浮动垃圾
G1整堆多线程并发整体标记-整理/局部复制可预测停顿详见 G1收集器原理,JDK9 默认
ZGC整堆几乎全并发染色指针+读屏障<10ms 停顿详见 ZGC特性,超大堆

3. 默认收集器演进:

  • JDK 8:Parallel Scavenge + Parallel Old(吞吐量优先)
  • JDK 9 ~ 至今:G1
  • JDK 11+:ZGC/Shenandoah 实验→转正(按版本)

4. 吞吐量 vs 停顿时间(核心权衡):

  • 吞吐量 = 运行用户代码时间 /(用户代码时间 + GC 时间)。批处理、科学计算等后台任务关注吞吐 → Parallel 系列。
  • 停顿时间(STW 时长):在线服务、对延迟敏感 → CMS/G1/ZGC。
  • 两者难以兼得:要低停顿就得并发收集,并发会占 CPU、降低吞吐。
面试回答(2分钟版)

HotSpot 的经典收集器按分代分两类。新生代有三个:Serial 是单线程的,用复制算法,简单高效,适合客户端和小堆;ParNew 是 Serial 的多线程版本,它最大的特点是唯一能和 CMS 搭配的新生代收集器;Parallel Scavenge 也是多线程复制,但它的目标是吞吐量,可以设置吞吐量大小还能自适应调节。老年代有三个:Serial Old 单线程标记-整理,常作为 CMS 失败的后备;Parallel Old 是 Parallel Scavenge 的老年代搭档,多线程标记-整理,这俩组合是 JDK8 的默认收集器,主打吞吐量;CMS 用标记-清除追求低停顿,但有内存碎片和浮动垃圾的问题。再往后就是不分代、面向整堆 Region 的 G1,是 JDK9 之后的默认,再往后是停顿可以做到 10ms 以内的 ZGC。选型的核心就是吞吐量和停顿时间的权衡:批处理这种后台任务选 Parallel 系列追吞吐,在线服务对延迟敏感就选 CMS、G1 或 ZGC 追低停顿,但低停顿要并发收集,会多占 CPU、牺牲一点吞吐。

追问与易错

追问方向:

  • “ParNew 和 Parallel Scavenge 都是多线程新生代,区别是什么?”→ ParNew 目标是配合 CMS 做低停顿,能和 CMS 搭配;Parallel Scavenge 目标是吞吐量,有自适应调节,但不能和 CMS 搭配。关注点不同:一个低停顿、一个高吞吐
  • “为什么只有 ParNew 能配 CMS,Parallel Scavenge 不行?”→ 历史实现原因,CMS 和 Parallel Scavenge 的框架代码不兼容(Parallel Scavenge 没有用 HotSpot 那套分代框架),所以 CMS 只能搭 Serial 或 ParNew
  • “Serial 单线程为什么还存在?多线程不是更快吗?”→ 单线程没有线程交互/切换开销,在客户端模式、小内存(几十到一两百 MB)场景下停顿可控且简单高效;嵌入式、桌面程序仍适用
  • “什么是吞吐量优先?怎么配置?”→ Parallel Scavenge 用 -XX:MaxGCPauseMillis 控制最大停顿、-XX:GCTimeRatio 控制吞吐量比例,-XX:+UseAdaptiveSizePolicy 让 JVM 自动调新生代大小和晋升阈值
  • “现在生产上还用 CMS / Parallel 吗?”→ CMS 在 JDK9 被标记废弃、JDK14 移除;新项目主流是 G1,超大堆低延迟用 ZGC;Parallel 仍适合纯吞吐的离线批处理

易错点:

  • ❌ “Parallel 和 CMS 都是并行收集器所以能搭配”——Parallel Scavenge 不能配 CMS,只有 ParNew 能
  • ❌ 混淆「并行 Parallel」(多条 GC 线程同时干活,用户线程仍 STW)和「并发 Concurrent」(GC 线程和用户线程同时运行)
  • ❌ “单线程一定比多线程慢”——小堆下 Serial 因无切换开销反而更优