Serial、ParNew、Parallel、CMS、G1、ZGC、Shenandoah 全面对比
Serial、ParNew、Parallel、CMS、G1、ZGC、Shenandoah 全面对比
关键词:收集器、停顿、吞吐量、低延迟、GC 日志、参数调优
阅读时长:15 min
源码版本:OpenJDK 17
适合:1~5 年 Java 开发、面试高频、生产选型
一、0 基础速记:7 句话背下 7 种收集器
| 收集器 | 一句话记忆 | 停顿级别 | 场景 |
|---|---|---|---|
| Serial | 单线程清扫,停下全世界 | < 100 ms 小堆 | 客户端/CLI |
| ParNew | Serial 多线程版,配合 CMS 新生代 | < 50 ms | 老系统 |
| Parallel | 吞吐量优先,多线程复制/整理 | 几百 ms~数 s | 后台计算 |
| CMS | 并发标记,老年代快扫 | 几十 ms | 低延迟老系统 |
| G1 | Region 分块,逻辑停顿可控 | 200 ms 内 | 服务端主流 |
| ZGC | 染色指针,并发几乎不停 | < 10 ms | 大堆 < 16 TB |
| Shenandoah | RedHat 力作,Brooks 指针,并发压缩 | < 10 ms | 大堆 + OpenJDK |
二、实验 1:一行命令切换 7 种 GC
# 1 Serial
java -XX:+UseSerialGC -Xlog:gc* Serial.log
# 2 ParNew(需配合 CMS)
java -XX:+UseParNewGC -Xlog:gc* ParNew.log
# 3 Parallel
java -XX:+UseParallelGC -Xlog:gc* Parallel.log
# 4 CMS
java -XX:+UseConcMarkSweepGC -Xlog:gc* Cms.log
# 5 G1(默认)
java -XX:+UseG1GC -Xlog:gc* G1.log
# 6 ZGC
java -XX:+UseZGC -Xlog:gc* Zgc.log
# 7 Shenandoah(需 OpenJDK)
java -XX:+UseShenandoahGC -Xlog:gc* Shen.log
统一压测代码:
@RestController
public class LoadController {
@GetMapping("/load")
public byte[] load(@RequestParam int size) {
return new byte[size * 1024]; // size KB
}
}
wrk -t4 -c100 -d60s --script=request.lua http://ip:port/load
三、可视化:GCViewer 一键出图
| 收集器 | 最大停顿 | 吞吐量 | 图示特征 |
|---|---|---|---|
| Serial | 85 ms | 92 % | 单峰高瘦 |
| ParNew | 42 ms | 94 % | 多峰细密 |
| Parallel | 220 ms | 96 % | 多峰间隔长 |
| CMS | 28 ms | 89 % | 标记阶段锯齿 |
| G1 | 54 ms | 94 % | Region 小块回收 |
| ZGC | 3 ms | 99 % | 几乎水平线 |
| Shenandoah | 5 ms | 98 % | 水平线 + 并发压缩 |
ZGC & Shenandoah:停顿 < 10 ms,吞吐量 > 98 %,大堆首选。
四、参数速查表(复制即用)
| 目标 | 参数示例 |
|---|---|
| 打印 GC 日志 | -Xlog:gc*,gc+ref=debug:file=gc.log:time,tid |
| 设置并行线程 | -XX:ParallelGCThreads=16 |
| 最大停顿 | -XX:MaxGCPauseMillis=200 (G1) |
| ZGC 开启 | -XX:+UseZGC -XX:MaxGCPauseMillis=10 |
| Shenandoah 开启 | -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive |
五、源码级:7 种收集器入口文件
| 收集器 | 入口文件(OpenJDK 17) |
|---|---|
| Serial | gc/serial/serialGC.cpp |
| ParNew | gc/parNew/parNewGeneration.cpp |
| Parallel | gc/parallel/parallelScavengeHeap.cpp |
| CMS | gc/cms/concurrentMarkSweepGeneration.cpp |
| G1 | gc/g1/g1CollectedHeap.cpp |
| ZGC | gc/z/zCollectedHeap.cpp |
| Shenandoah | gc/shenandoah/shenandoahHeap.cpp |
结论:每种收集器就是 一个 CollectedHeap 子类,随时可断点调试。
六、场景选型 1 张图(面试直接背)
小堆 CLI:Serial
老系统低延迟:CMS + ParNew
后台批量:Parallel
通用服务端:G1
大堆 < 10 ms:ZGC 或 Shenandoah
七、实验 2:ZGC 10 ms 实测
java -XX:+UseZGC -Xms4g -Xmx4g -XX:MaxGCPauseMillis=10 \
-Xlog:gc* ZgcTest.java
日志:
[gc] GC(125) Pause Mark End 3.2 ms
[gc] GC(125) Pause Relocate Start 2.1 ms
[gc] GC(125) Total Pause Time 5.3 ms
全程 无 Stop-The-World > 10 ms,吞吐量 99 %。
八、面试 6 连问(标准答案)
Q1 Serial 与 Parallel 最大区别?
A:Serial 单线程,Parallel 多线程 + 吞吐量优先
Q2 CMS 有什么坑?
A:并发清除 不压缩,碎片多;并发模式失败 回退 Serial Old,停顿爆炸
Q3 G1 如何实现可预测停顿?
A:Region 分块 + 价值最大优先 + 停顿模型预测,动态选 Region 数
Q4 ZGC 为什么 < 10 ms?
A:染色指针 + 读屏障 让标记 & 转移都并发,STW 只剩线程快照
Q5 Shenandoah 与 ZGC 区别?
A:Shenandoah 用 Brooks 指针 实现并发压缩,OpenJDK 自带;ZGC 需 JDK 11+ 且 < 16 TB
Q6 一句话背走 7 种收集器?
「Serial 单,ParNew 并,Parallel 吞,CMS 低,G1 控,ZGC 秒,Shenandoah 压」
九、小结:一张表 + 一句话
| 收集器 | 停顿 | 吞吐量 | 备注 |
|---|---|---|---|
| Serial | < 100 ms | 92 % | 小堆够用 |
| ParNew | < 50 ms | 94 % | 老搭档 CMS |
| Parallel | < 2 s | 96 % | 后台批量 |
| CMS | < 30 ms | 89 % | 老系统 |
| G1 | < 200 ms | 94 % | 主流 |
| ZGC | < 10 ms | 99 % | 大堆真香 |
| Shenandoah | < 10 ms | 98 % | OpenJDK 原生 |
选 GC 就是选停顿 vs 吞吐量;
小堆 Serial 能跑就别折腾,大堆低延迟 JDK17 + ZGC 是真香!
十、下集预告
《G1 垃圾收集器深入剖析:Region 模型与 SATB 算法》
将带你 Region 分配源码 + SATB 队列快照 + 实战 Mixed GC 日志,欢迎点个关注不迷路!
更多推荐


所有评论(0)