g1调优核心是动态平衡停顿可控、吞吐合理、内存高效三大目标,关键在理解其行为逻辑:设合理-xx:maxgcpausemillis(推荐150–250ms),禁用-xmn,关注humongous region问题,启用详细gc日志定位瓶颈。

G1垃圾回收器的性能调优,核心不是堆参数堆砌,而是围绕“停顿可控、吞吐合理、内存高效”三个目标做动态平衡。它不靠固定大小的新生代硬约束,而是通过Region划分和回收价值评估,自主调节每次GC的工作量。调优的关键,在于理解G1的行为逻辑,再针对性干预。
明确停顿目标:-XX:MaxGCPauseMillis 是起点,不是上限
这个参数告诉G1“你每次STW尽量别超过X毫秒”,G1会据此反推能处理多少Region、该用多大年轻代、要不要提前触发Mixed GC。但它不是强制截止时间,实际停顿可能略高——尤其在堆压力大或对象晋升快时。
- 设为100ms不等于每次停顿都≤100ms,而是G1会努力让90%以上的GC满足该目标
- 值设得太小(如50ms),G1被迫缩小年轻代、频繁Young GC,反而增加总STW时间与CPU开销
- 值设得太大(如500ms),G1倾向延迟Mixed GC,老年代堆积加快,最终可能触发代价更高的Full GC
- 推荐起步值:150–250ms(中等延迟服务),再根据GC日志中Actual Pause Time分布微调
避免手动干预年轻代:别用 -Xmn 或 -XX:NewRatio
G1的年轻代大小是动态浮动的,这是它实现停顿控制的核心机制。一旦你用-Xmn固定了年轻代,就等于关掉了G1的自适应引擎。
- 固定年轻代后,G1无法根据停顿目标增减Eden区数量,容易造成“要么停顿超时,要么回收太少”两难
- 观察GC日志中“Eden regions”字段的变化幅度,若长期恒定,大概率已被人为锁死
- 真正需要调整的是整体堆大小(-Xmx/-Xms)和停顿目标,让G1自己算出合适的年轻代范围
关注大对象与Humongous Region问题
单个对象超过Region大小一半(默认约1MB)就会被直接分配到Humongous Region。这类区域不参与常规Young GC,只能等到Mixed GC或Full GC才回收,极易造成内存浪费和碎片化。
- 用jcmd
VM.native_memory summary或GC日志中的Humongous allocations统计确认是否存在高频大对象分配 - 若应用确实需大量大对象(如缓存图片、序列化数据),可适当增大Region尺寸:-XX:G1HeapRegionSize=2M或4M
- 启用早期回收:-XX:+G1ReclaimDeadHumongousObjectsAtYoungGC,让死亡的大对象在Young GC阶段就被清理
- 代码层避免无节制创建byte[]、String、ArrayList等易膨胀结构,优先复用或流式处理
监控与诊断:用对日志,才能看清问题本质
光看GC次数和耗时不够,要深入阶段耗时分布,才能定位瓶颈。
- 启用详细GC日志:-Xlog:gc*,gc+heap=debug,gc+ergo*=trace:file=gc.log:time,tags,uptime
- 重点关注阶段耗时:Ext Root Scanning(根扫描)、Update RS(记忆集更新)、Object Copy(对象复制)、Termination(终止等待)
- 若Update RS占比高,说明跨Region引用频繁,可尝试增加并发Refinement线程数:-XX:G1ConcRefinementThreads=6
- 若Evacuation Failure频繁出现,代表内存分配速率远超回收能力,需检查对象生命周期或考虑扩容堆











