关键在于选对回收器、设准目标停顿、管住对象生命周期:g1适用于4–16gb堆且停顿可控,zgc/shenandoah可逼近亚毫秒但需匹配jdk版本与业务兼容性;禁用parallel/serial gc等高停顿默认回收器。

能把 JVM 垃圾回收停顿压到毫秒级,关键不是堆调大、参数堆多,而是选对回收器 + 设准目标 + 管住对象生命周期。G1 在中等规模堆(4–16GB)上最稳,ZGC 或 Shenandoah 才是真正逼近亚毫秒的选项——但得看 JDK 版本和业务是否适配。
选对垃圾收集器是前提
默认 Parallel GC 或 Serial GC 天然不适合低延迟场景,单次 Minor GC 就可能 200ms+,Full GC 更是动辄秒级。必须主动切换:
- G1 GC:JDK 8u20 及以上广泛可用,-XX:+UseG1GC 必须显式开启;适合堆 ≤16GB、要求平均停顿
- ZGC:JDK 11+ 支持,64GB 堆下平均停顿可稳定在
- Shenandoah:JDK 12+,停顿表现接近 ZGC,对内存带宽更友好,适合容器化环境或 CPU 资源受限但内存充足的情况
- CMS 已废弃(JDK 14 起移除),不建议新系统使用
设准 -XX:MaxGCPauseMillis 目标值
这个参数不是“保证值”,而是 G1/ZGC 的优化导向指令。设得太激进反而坏事:
- G1 推荐从 200ms 起步(默认值),观察 GC 日志中 Actual Pause 分布;若 P90 在 150ms 内,可尝试下调至 150ms
- 设
- ZGC 不依赖该参数,它靠并发标记与染色指针天然规避大部分 STW,但需配合 -XX:+UnlockExperimentalVMOptions -XX:+UseZGC
避免对象过早晋升老年代
老年代对象堆积会触发 Mixed GC(G1)或增加 ZGC 的重映射压力,直接拉高停顿。重点控三件事:
- 检查 Survivor 区是否过小:-XX:SurvivorRatio=6 比默认 8 更利于短期对象自然消亡,减少晋升
- 避免创建 >½ Region 大小的巨型对象(Humongous Object),它们绕过年轻代直入老年代;可通过 -XX:G1HeapRegionSize=2m 控制 Region 粒度
- 禁用 -Xmn 或 -XX:NewRatio(G1 下无效且有害),让 G1 自主浮动年轻代大小,这是它控停顿的核心机制
配套必须做的基础配置
再好的回收器,没配稳底座也白搭:
- 固定堆大小:-Xms=-Xmx,避免运行时扩容触发额外 GC 和内存抖动
- 启用详细 GC 日志:-Xlog:gc*,gc+heap=debug,gc+ergo*=trace:file=gc.log::time —— 不看日志,所有调优都是猜
- 关闭字符串去重:-XX:-UseStringDeduplication(除非确认有海量重复字符串),它会在 STW 阶段加锁扫描,徒增耗时
- 对 ZGC,建议搭配 -XX:+UseLargePages 提升 TLB 效率,尤其在大堆场景下










