Java主流垃圾回收器有6种:Serial、Parallel、CMS(已废弃)、G1、ZGC和Shenandoah;选择依据是应用运行环境,如机器配置与停顿要求,而非版本新旧。

Java里常见垃圾回收器有6种主流选择:Serial、Parallel、CMS(已废弃)、G1、ZGC 和 Shenandoah。选哪个不看“新不新”,而要看你的应用跑在哪——是4核2G的后台小服务?还是堆内存80GB、要求停顿
怎么一眼判断该用 Serial 还是 Parallel?
关键不是“单线程 vs 多线程”,而是你是否在追求吞吐量,以及有没有多核可用。
-
Serial GC(-XX:+UseSerialGC)只适合单核 CPU 或极轻量场景(如嵌入式、单元测试JVM),它会全程 STW,但启动快、内存开销最小; -
Parallel GC(-XX:+UseParallelGC)是 JDK8/9 默认的 Server 模式收集器,目标明确:最大化吞吐量;它新生代+老年代都并行,但每次 GC 仍会 STW —— 所以如果你的接口 P99 延迟卡在 500ms,别怪 Parallel,它压根不是为低延迟设计的; - 误区:很多人以为“开了多线程就一定比 Serial 快”。错。如果堆只有 512MB,Serial 可能比 Parallel 更快,因为 Parallel 启动线程、同步状态本身就有开销。
G1 是不是“万能默认”?什么时候它反而更糟?
G1(-XX:+UseG1GC)确实是 JDK9+ 的默认 GC,但它不是银弹——尤其在小堆或高分配速率场景下容易翻车。
- G1 把堆切成
Region,靠预测模型控制停顿时间(比如-XX:MaxGCPauseMillis=200),但这个值只是“目标”,不是保证; - 当对象分配速率远高于回收速率(如突发大量短生命周期对象),G1 会频繁触发
Mixed GC,甚至退化成 Full GC,STW 时间飙升; - 小堆(
- 必须配:
-XX:+UseStringDeduplication(减少字符串重复)和-XX:G1HeapRegionSize(避免 Region 过小导致元数据膨胀)。
CMS 已废弃,ZGC/Shenandoah 又太新?那生产环境到底怎么稳着用?
CMS 在 JDK14 彻底移除,别再用 -XX:+UseConcMarkSweepGC;ZGC 和 Shenandoah 虽强,但对 JDK 版本和 OS 有硬性要求(ZGC 要 JDK11+,Linux only;Shenandoah 在 OpenJDK 12+ 官方支持)。
立即学习“Java免费学习笔记(深入)”;
- 如果你用的是 JDK8/LTS,G1 是最现实的平衡选择,但务必开启日志:
-Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps; - JDK17+ 生产环境推荐 ZGC,但注意:它要求
-XX:+UnlockExperimentalVMOptions(JDK17)或直接去掉(JDK21+),且不能与UseCompressedOops在大堆(>4TB)下共存; - 常见坑:
ZGC默认启用并发类卸载(-XX:+ZClassUnloading),但某些老框架(如早期 Spring Boot 2.3)反射缓存未清理,会导致Metaspace OOM;关掉它:-XX:-ZClassUnloading; - 别迷信“毫秒级停顿”——ZGC 的 STW 只剩初始标记和最终标记两个极短阶段,但若发生
Allocation Stall(应用线程等不到空闲 Region),照样卡住,这时得调-XX:ZCollectionInterval或加大堆。
真正决定 GC 表现的,从来不是参数本身,而是对象生命周期分布和分配速率。上线前务必用真实流量压测,而不是只看 HelloWorld 的 GC 日志。一个没被压出来的 Concurrent Mode Failure,往往比选错 GC 更致命。










