G1是JVM层垃圾回收器,非Apache架构直接管理;JDK 8u20+需显式启用,JDK 9+默认启用;禁用-Xmn和-XX:NewRatio以保障G1动态调优能力。

Apache架构本身不直接管理Java垃圾回收——真正起作用的是运行在其上的Java应用(比如用Tomcat、Spring Boot打包部署的服务),而G1是JVM层的回收器。只要你的后端是Java进程,且JVM版本 ≥ 7u4(推荐 ≥ 8u20 或更高),就可以启用G1并显著改善大堆下的吞吐与延迟平衡。
确认当前是否已启用G1及默认行为
很多团队误以为加了 -XX:+UseG1GC 就万事大吉,其实G1在不同JDK版本下默认策略差异很大:
- JDK 8u20+:G1可用,但**不是默认**;需显式启用
- JDK 9+:G1是**默认GC**,无需额外参数(除非你覆盖了它)
- JDK 17+:ZGC/Shenandoah可选,但G1仍是生产主力
验证方式很简单,在启动脚本或容器启动命令中检查是否含 -XX:+UseG1GC;再用 jstat -gc 查看输出中是否有 G1 字样(如 GC 列显示 G1 Young Generation)。若看到 PSYoungGen 或 ParNew,说明还在用Parallel GC。
必须禁用的参数:-Xmn 和 -XX:NewRatio
G1的核心能力是动态调整年轻代大小来满足停顿目标。一旦你硬编码了 -Xmn 或 -XX:NewRatio,等于把G1的“自动油门”焊死,它就退化成一个低效的固定代际回收器。
常见错误现象:
- 明明设了
-XX:MaxGCPauseMillis=200,但实际STW仍频繁突破500ms - 年轻代Region数长期卡在初始值,无法随负载增长扩容
- Mixed GC频率骤降,老年代持续膨胀,最终触发
Pause Full (G1 Compaction Pause)
正确做法:只保留 -Xms 和 -Xmx(建议设为相等,避免堆震荡),其他代际相关参数全部删掉。
关键调优参数:从吞吐出发的务实配置
Apache系Java服务(如Tomcat集群)通常面临中高并发+中大堆(8–32G)场景。此时G1的目标不是极致低延迟,而是稳态吞吐——即在可控停顿下尽量多做业务事。
推荐组合(以16G堆为例):
-
-Xms16g -Xmx16g:消除堆伸缩开销 -
-XX:+UseG1GC:明确启用 -
-XX:MaxGCPauseMillis=200:给G1一个现实目标(别设50ms,那会严重牺牲吞吐) -
-XX:G1HeapRegionSize=2M:避免默认1M导致Region过多(2048个Region上限下,16G堆默认约8K Region,超出上限会自动上调) -
-XX:+G1UseAdaptiveIHOP(JDK 10+ 默认开启):让G1根据历史晋升速率动态决定何时启动并发标记,比静态-XX:InitiatingOccupancyPercent更稳
注意:-XX:G1HeapRegionSize 必须是2的幂(1/2/4/8/16/32M),且影响大对象判定——若业务有较多1–3MB缓存对象,设2M可避免它们被误判为Humongous对象,减少疏散失败风险。
容易被忽略的监控点:Humongous Allocation 和 Evacuation Failure
G1里最隐蔽的性能杀手不是Full GC,而是频繁的Humongous分配和疏散失败:
- 日志中出现
Humongous allocation:说明有对象 > RegionSize/2,正被塞进连续Humongous Region,这会快速耗尽老年代碎片空间 - 出现
Evacuation Failure:G1尝试移动对象时发现没足够空Region,被迫退化为单线程Full GC,停顿可达秒级
排查方法:加 -Xlog:gc*,gc+heap=debug(JDK 10+),重点搜 humongous 和 evacuation。解决方案不是调参,而是代码侧收敛大对象生命周期——比如用池化替代反复new byte[2M],或改用off-heap缓存。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











