zgc是≤10ms停顿且堆≥4gb场景的首选,需linux x64/aarch64+jdk17+、固定堆大小(-xms=-xmx)、显式启用-xx:+usezgc,java15起支持16tb堆,生产建议8gb–32gb起步验证。

低延迟应用的核心诉求是控制单次 GC 停顿(STW)在可接受范围内,比如 Web API、实时风控、游戏服务等场景,通常要求 P99 停顿 ≤ 200ms,甚至压到 10ms 级别。选对收集器不是看“新不新”,而是匹配堆大小、JDK 版本、平台限制和实际分配行为。
明确延迟目标再定回收器类型
停顿要求直接决定候选范围:
- ≤ 10ms 且堆 ≥ 4GB → ZGC 是首选,前提是运行在 Linux x64/AArch64 + JDK 17 或更高版本;Java 15 起已取消堆上限,支持至 16TB,但生产建议从 8GB–32GB 起步验证
- 100–200ms 且堆 4–16GB → G1 GC 更稳妥,它比 CMS 易用(CMS 已于 JDK 14 移除),能通过 -XX:MaxGCPauseMillis=200 主动引导停顿预期
- 纯吞吐优先、偶尔容忍 500ms+ 停顿 → Parallel GC 反而更稳,尤其适合批处理或后台任务,别为“低延迟”标签强行换 G1
避开常见误配陷阱
参数调优必须服从回收器底层逻辑,不是越细越好:
- G1 中乱设 -XX:G1NewSizePercent 会破坏其自适应年轻代策略;-XX:G1HeapRegionSize 默认 2MB 覆盖绝大多数场景,改小易拖慢并发标记,改大会导致大对象直入 Humongous 区引发碎片
- ZGC 不需要调新生代参数(它不分代),但必须固定堆大小:-Xms 与 -Xmx 相等,避免动态伸缩干扰低延迟稳定性
- -XX:MaxGCPauseMillis 设 50ms 往往适得其反——G1 会频繁触发混合回收、增加 CPU 开销;建议从 200ms 起步,结合 GC 日志中 G1 Evacuation Pause 实际耗时微调
验证是否真“低延迟”,不止看 GC 日志
真实延迟还受非 GC 因素影响,监控不能只盯 pause 时间:
- 用 jstat -gc
查 ZGC 的 ZGC pauses 总和,同时关注安全点同步耗时(Safepoint sync time),它可能比 GC 本身还长 - 开启 -Xlog:gc*:file=gc.log 后,重点看每次 Young (Mixed) 的实际耗时分布,而非平均值;P99 > 200ms 就说明目标未达成
- 检查是否频繁发生 Humongous Allocation(G1)或元空间 OOM(ZGC),这类问题常伪装成 GC 延迟,实则是对象生命周期或类加载设计不合理
平台与版本约束必须前置确认
再好的回收器跑不起来等于零:
- ZGC 仅支持 Linux x64 / AArch64,Windows/macOS 不可用;Shenandoah 在 JDK 16+ 才默认启用,JDK 11–15 需加 -XX:+UnlockExperimentalVMOptions
- JDK 8 默认 Parallel GC,JDK 9–10 默认 G1,JDK 11+ ZGC 可用但需显式启用,JDK 17+ 才推荐用于生产
- 堆超过 4TB 时,ZGC 要求开启压缩指针(UseCompressedOops),否则会失效——这点极易被忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











