应优先选用匹配堆大小的低延迟GC回收器:≤4GB用G1,8GB–64GB用ZGC,≥64GB或严苛延迟场景选Shenandoah;同时优化堆结构、控制对象生命周期,并通过GC日志与jstat验证效果。

高并发系统对响应延迟极为敏感,GC停顿是主要瓶颈之一。降低延迟的关键不是“调参数”,而是选对回收器、配准堆结构、控制对象生命周期——让GC尽可能少停、每次停得短、停得可预测。
优先选用低延迟回收器
不同回收器的停顿特性差异巨大,必须按堆大小和延迟要求匹配:
-
堆 ≤ 4GB:G1 是稳妥选择,启用
-XX:+UseG1GC,配合-XX:MaxGCPauseMillis=200(目标值,非硬限制),JVM会动态调整回收节奏; -
堆 8GB–64GB:ZGC 更优,用
-XX:+UseZGC -Xmx32g,99%停顿稳定在 10ms 内,且不随堆增大而恶化; - 堆 ≥ 64GB 或延迟要求严苛(如:ZGC 仍是首选,实测在 128GB 堆下平均停顿仍低于 8ms;
- CMS 已被 JDK 14+ 移除,G1 在 JDK 9+ 成为默认,ZGC 自 JDK 15 起正式生产就绪,不建议回退旧回收器。
堆内存配置要避免动态伸缩
频繁扩容/缩容会触发额外 GC 和内存拷贝,加剧延迟抖动:
- 设
-Xms与-Xmx相等,例如-Xms16g -Xmx16g,消除启动期和运行中堆调整开销; - 总堆建议占物理内存 50%–70%,预留空间给元空间、直接内存和 OS 缓存;
- ZGC 不依赖新生代/老年代比例,无需设置
-Xmn或-XX:NewRatio;G1 也应交由 JVM 自动管理代际大小,强行固定反而干扰其预测模型。
减少 GC 触发频率和对象晋升压力
延迟不仅来自 GC 停顿本身,更来自对象频繁创建、过早晋升、跨代引用带来的额外开销:
立即学习“Java免费学习笔记(深入)”;
- 控制线程栈大小:
-Xss256k(而非默认 1M),高并发服务常启数千线程,节省数百MB栈内存,间接降低 GC 压力; - 避免大对象直接进入老年代:单个对象 > ½ Region 大小(G1 默认约 512KB)会被标记为 Humongous,回收代价高;检查日志中
Humongous Allocation频次,拆分大缓存或改用池化对象; - 缩短对象生命周期:业务代码中及时置 null、复用对象、减少临时集合创建,让对象在 Eden 区内就被回收,避免 Survivor 区拷贝和老年代晋升。
用日志和工具验证效果
调参后必须观测真实行为,不能仅凭理论推断:
- 加参数
-Xlog:gc*,gc+heap=debug,gc+ref=debug:file=gc.log:tags,time,uptime(JDK 10+),记录每次 GC 类型、耗时、回收量; - 用
jstat -gc <pid>查看 YGC/FULL GC 频次、平均耗时、内存使用趋势; - 对比关键指标:99 分位响应时间、GC 暂停总时长占比(理想应


















