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 日志,欢迎点个关注不迷路!

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐