堆大小和cpu核数决定回收器下限:≤100mb用serialgc,100mb~6gb多核优先g1gc,≥6gb延迟敏感选zgc或shenandoahgc,单核禁用并行/并发回收器。

堆大小和CPU核数决定回收器下限
选错回收器的第一步,往往不是参数调得不对,而是连基础硬件匹配都错了。JVM不会替你兜底——比如在单核机器上硬塞 -XX:+UseParallelGC,线程争抢反而拖慢GC;又比如给 8GB 堆配 -XX:+UseSerialGC,一次 Full GC STW 能卡住应用好几秒。
- 堆 ≤ 100MB:用
-XX:+UseSerialGC,单线程无开销,STW 可控 - 100MB ~ 6GB:多核下优先
-XX:+UseG1GC(JDK9+ 默认),CMS 已废弃,别再试 - 堆 ≥ 6GB 且延迟敏感:直接上
-XX:+UseZGC(JDK11+)或-XX:+UseShenandoahGC,否则 G1 的-XX:MaxGCPauseMillis=200很难稳住 - 单核/CPU受限环境:禁用所有并行/并发回收器,只留 Serial 或 CMS(仅 JDK8)
吞吐量优先还是延迟优先?别折中
“既要又要”在这里是陷阱。Parallel GC 能把 GC 时间压到总运行时间的 1%,但单次老年代回收可能停顿 2 秒;ZGC 把每次停顿锁死在 10ms 内,但吞吐量会比 Parallel 低 5%~10%。业务场景不明确时,先问自己一句:用户能感知几秒卡顿?后台任务跑慢一分钟是否可接受?
- 批处理、ETL、报表生成 → 选
-XX:+UseParallelGC,配-XX:GCTimeRatio=99 - Web API、实时查询、订单支付 → 必须
-XX:+UseG1GC或更高,禁用 Parallel - 高频交易、实时风控、AR/VR 后端 → 只考虑
-XX:+UseZGC,且确认 JDK ≥ 17(ZGC 生产就绪始于 JDK17)
CMS 已淘汰,G1 不是万能解药
CMS 在 JDK9 被标记为废弃,JDK14 彻底移除。现在还看到配置里有 -XX:+UseConcMarkSweepGC,基本等于技术债未清。而 G1 虽是默认,但容易被误用:它对小堆( 256KB)没做适配时,会频繁触发 Humongous 分配失败,导致退化成 Full GC。
- 老项目迁移到 JDK11+:删掉所有 CMS 参数,用 G1 替代,加
-XX:+UseStringDeduplication减少字符串冗余 - 堆 > 4GB 且存在大量大对象:启用
-XX:+UseG1GC -XX:G1HeapRegionSize=4m(按对象大小对齐 Region) - 频繁出现
to-space exhausted或evacuation failure日志:说明 G1 并发回收跟不上分配速度,要么升 ZGC,要么检查对象晋升逻辑
验证不是靠猜,而是看日志和指标
光改参数不看效果,等于没调。JVM 不会主动告诉你哪里错了,它只会默默让 GC 频率升高、停顿变长、Full GC 突然暴增。真正有效的验证只有两件事:开 GC 日志 + 对比关键数字。
- 必须加的启动参数:
-Xlog:gc*:file=/var/log/jvm/gc.log:time,tags,level(JDK10+)或-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/path/gc.log(JDK8) - 重点关注三项:
Young GC 频率(理想几十秒一次)、Old GC 平均耗时(G1 应 Full GC 次数(非零即异常) - 发现
Concurrent Mode Failure(CMS)或G1 Evacuation Pause耗时飙升 → 不是调MaxGCPauseMillis,而是该扩容堆或切 ZGC










