选JVM垃圾回收器需按业务类型、硬件资源和GC表现三维度取舍:吞吐优先用Parallel,延迟敏感选G1/ZGC/Shenandoah,小内存用Serial;堆大小与CPU核数决定回收器适用性;须结合GC日志调优,避免误用CMS或强行套用ZGC。

选 JVM 垃圾回收器,本质是做取舍:要么保吞吐量,要么压停顿时间,没有“全能型”。关键不在参数多不多,而在是否匹配你的应用真实负载特征——比如一个支付接口每秒扛 5000 请求,哪怕堆只设 2G,Serial 也会让用户等出幻觉;而一个夜间跑报表的批处理任务,硬上 ZGC 反而浪费 CPU 资源。
看业务类型:吞吐量优先 or 延迟敏感
这是最直接的决策起点。
-
后台任务(ETL、日志归档、离线计算):选 Parallel GC。它用多线程抢时间,目标是让业务逻辑运行得越久越好。比如设置
-XX:GCTimeRatio=99,意味着 GC 总时间不能超过总运行时间的 1%。 - 在线服务(API 接口、Web 应用、交易系统):停顿必须短。CMS 曾是主流,但已废弃;现在推荐 G1(JDK 9+ 默认),或更高阶的 ZGC/Shenandoah(JDK 11+ 支持)。它们把单次 STW 控在 10ms 内,对用户无感。
- 嵌入式或桌面小工具:内存 ≤ 1GB、单核 CPU,Serial GC 反而是最轻量、最稳的选择,没线程调度开销,STW 时间也短。
看硬件资源:CPU 核心数与堆大小
回收器不是孤立工作的,它得和机器配置咬合。
- 堆小于 4GB,且 CPU 少于 4 核:Parallel GC 或 Serial GC 都可,别强行上 G1 —— 它的并发线程和区域管理反而拖慢小堆。
- 堆 ≥ 8GB,多核(≥8 核):G1 开始体现价值。它按 Region 划分堆,能预测性地控制停顿,还能通过
-XX:MaxGCPauseMillis=20设定目标停顿上限。 - 堆 ≥ 16GB,延迟要求严苛(如金融行情、实时风控):ZGC 是更优解。它采用着色指针 + 并发标记/移动,停顿基本稳定在 10ms 内,且不受堆大小影响。
看 GC 行为表现:别只盯参数,要观察实际指标
配置再漂亮,不看日志等于盲调。
- 加
-Xlog:gc*:file=gc.log:time,tags(JDK 10+)或-XX:+PrintGCDetails -XX:+PrintGCTimeStamps(旧版),抓真实 GC 频率、停顿时长、晋升速率。 - 重点关注:Full GC 是否频繁?(说明老年代压力大,可能对象过早晋升或内存泄漏);Minor GC 间隔是否急剧缩短?(Eden 区太小或对象存活率高);GC 后老年代使用率是否持续上涨?(CMS 失败或 G1 混合回收跟不上)。
- 别迷信“默认值”:JDK 8 默认 Parallel,JDK 11+ 默认 G1,但默认 ≠ 最适配。电商大促前换掉默认回收器,是常见预案。
避坑提醒:几个高频误用场景
这些错误,线上故障里反复出现。
- 用 Parallel GC 跑 Web API:吞吐量上去了,但一次 Full GC 停顿 2 秒,用户请求全超时,接口监控直接告警爆炸。
- 给小内存服务硬配 ZGC:ZGC 需要额外元数据空间和着色指针支持,在 2GB 堆下启动反而慢,还吃更多 CPU。
-
忽略 CMS 已被移除:JDK 14 起彻底删除 CMS,JDK 17+ 不再支持。还在生产环境写
-XX:+UseConcMarkSweepGC,启动直接失败。 -
只调回收器,不调堆结构:比如用 G1 却把
-XX:NewRatio设成 2,强制年轻代过大,反而加剧 Mixed GC 压力。

















