gc日志末尾secs值即真实stw时间,是调优核心指标;需先排除to-space exhausted、evacuation failure、concurrent mode failure三类日志信号;g1下仅可调g1newsizepercent和g1maxnewsizepercent两个弹性边界参数。

直接看 GC 日志末尾的 secs 值,就是真实 STW 时间。它不是估算,而是操作系统实测的挂起时长。微调堆内存物理占比(比如年轻代占堆比例)不能靠拍脑袋,必须以这个数字为反馈闭环的核心指标。
先确认停顿是否真由堆占比失衡导致
不是所有高停顿都该调堆占比。优先排除三类日志信号:
- 出现
to-space exhausted→ 说明 Survivor 空间严重不足,对象被迫直入老年代,根源常是年轻代过小或SurvivorRatio过大 - 出现
evacuation failure→ 复制阶段放不下对象,典型因MaxTenuringThreshold设太高、对象滞留 Survivor 过久,或年轻代碎片化 - 出现
concurrent mode failure→ 老年代在并发标记中突然填满,往往因老年代实际可用空间太小,背后可能是年轻代占比过高、晋升太快,或G1ReservePercent设太低
这些关键词一定出现在 GC 日志的 Cause 字段或括号内,不 grep 就容易漏掉。
G1 下真正可调的堆占比参数只有两个弹性边界
G1 不允许你用 -Xmn 或 -XX:NewRatio 锁死年轻代大小,否则 MaxGCPauseMillis 会失效。你应该调的是:
-
-XX:G1NewSizePercent:年轻代最小占比(默认 5%) -
-XX:G1MaxNewSizePercent:年轻代最大占比(默认 60%)
例如设为 20 和 50,G1 就会在负载变化时,在 20%~50% 堆大小之间动态伸缩年轻代。这样既控住单次 Young GC 的停顿(年轻代越小,复制越快),又避免极端负载下年轻代被压得太小、GC 频率飙升。
结合停顿时长趋势反向校准区间
- 如果日志里
G1 Evacuation Pause (young)平均耗时稳定在 30ms 以内,但毛刺频繁冲到 80ms+,说明 G1 在预热期或压力突增时无法及时扩大年轻代 → 可适当提高G1MaxNewSizePercent(如从 50→60) - 如果大量
G1 Evacuation Pause (mixed)耗时 >100ms,且日志显示Old regions scanned数量多、Remembered Set处理时间长 → 往往是年轻代占比偏高,导致晋升对象多、老年代碎片重 → 应降低G1NewSizePercent(如从 20→15),同时检查G1MixedGCLiveThresholdPercent是否设得过高(默认 85,可试 75)
注意 Region 大小对占比效果的实际约束G1HeapRegionSize 默认自动推导,但若堆 >32GB 且业务对象普遍 300KB~800KB,建议显式设为 4m 或 8m。否则:
- Region 太大(如 16m),单个 Eden Region 承载对象过多,复制耗时不可控,再调年轻代占比也难压停顿
- Region 太小(如 1m),Region 总数暴涨,Remembered Set 元数据膨胀,反而拖慢并发阶段,间接拉长 Final Marking 等 STW 环节
不复杂但容易忽略:堆占比调整必须配合 MaxGCPauseMillis 目标值一起看。设 =30 却把 G1NewSizePercent 锁死在 40,G1 就失去弹性,停顿反而更抖。











