选对垃圾回收器关键在于匹配业务压力:吞吐优先用parallel gc,响应敏感用g1(亚毫秒级选zgc/shenandoah),小堆单核用serial gc;同时需结合堆大小与cpu核数适配。

选对垃圾回收器,关键不是看它新不新、参数多不多,而是看它能不能扛住你的真实业务压力。
先分清你的业务要什么:吞吐量优先,还是响应时间敏感
这是最根本的起点,直接决定回收器大方向:
- 后台批处理、ETL、报表生成这类任务,目标是单位时间完成最多工作——用 Parallel GC。它全程 STW,但线程并行、无协调开销,吞吐效率最高。JDK 8 默认就是它,JDK 9+ 虽改默认为 G1,但吞吐场景下主动切回 Parallel 反而更稳。
- Web API、支付接口、实时推荐等在线服务,用户等不了——必须压单次停顿。CMS 已废弃,G1 是通用主力(JDK 9+ 默认),目标停顿可设(如
-XX:MaxGCPauseMillis=200);若要求亚毫秒级(比如金融行情、风控决策),且运行在 Linux 64 位 + JDK 17+,可上 ZGC 或 Shenandoah。 - 嵌入式设备、桌面小工具、开发测试环境,堆 ≤ 1GB、单核 CPU——Serial GC 最轻量。没线程调度负担,STW 时间也短,强行上并发回收器反而拖慢。
再看机器能给什么:堆大小和 CPU 核数得匹配
回收器不是万能的,它得和硬件咬合才有效:
- 堆 Parallel 或 Serial 更合适。
- 堆 ≥ 8GB、CPU ≥ 8 核:G1 开始发挥优势。它按 Region 回收,能预测停顿,配合
-XX:G1HeapRegionSize控制大对象分配,避免 Humongous 打乱节奏。 - 堆 ≥ 16GB 且延迟严苛:ZGC 的着色指针 + 并发标记/移动机制,让停顿基本稳定在 10ms 内,且不受堆大小影响——但前提是分配速率平稳,元空间和压缩指针配置得当。
最后靠日志说话:参数只是假设,日志才是真相
再合理的配置,不看 GC 日志等于蒙眼调优:
- 用
-Xlog:gc*:file=gc.log:time,tags(JDK 10+)或-XX:+PrintGCDetails -XX:+PrintGCTimeStamps(旧版)抓真实数据。 - 重点盯三件事:Full GC 是否频繁(老年代压力大或内存泄漏)、Minor GC 间隔是否快速缩短(Eden 太小或对象存活率高)、GC 后老年代使用率是否持续爬升(混合回收跟不上晋升)。
- 别迷信
MaxGCPauseMillis。G1 只把它当目标,设太低(如 50ms)会引发高频并发标记和过早混合回收,CPU 占用飙升,停顿反而更抖。
几个典型误用要避开
这些坑在线上反复出现:
- 把 ZGC 当“银弹”塞进小内存服务:它需要额外元数据空间,堆太小反而增加开销。
- 在纯吞吐场景硬上 G1:它的低延迟设计自带协调成本,任务总耗时可能比 Parallel 还长。
- 忽略 CMS 已废弃的事实:JDK 9 起移除,JDK 14 彻底删除,继续用等于埋雷。
- 只调回收器,不查 GC Roots:对象不回收,十有八九是静态集合、缓存、监听器或 JNI 持有强引用,跟回收器无关。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











