ZGC真实STW时间取自日志中带[Pause]标签的PauseInitialMark和PauseFinalCleanup事件,单位毫秒,需结合GC(ID)对齐周期;必须启用-Xlog:gc*,gc+z=info才能捕获,非估算值。

Stop-The-World(STW)时间不是估算值,而是可精确提取的实测指标——关键在于选对GC类型、开对日志、抓准字段。
ZGC真实STW时间怎么取?
ZGC只有两个真正STW阶段:初始标记(PauseInitialMark)和最终清理(PauseFinalCleanup)。它们在日志中明确标有[Pause]前缀,单位是毫秒,不写单位但就是毫秒。
- 必须启用完整日志:
-Xlog:gc*,gc+z=info,缺一不可;只写gc+z=info不生效 - 同一GC周期内可能出现多次
PauseInitialMark(比如并发标记失败后回退),要结合GC(ID)字段对齐,不能简单grep "Pause"后累加 - 如果日志里完全没出现
Pause字样,说明要么没用ZGC,要么配置错误(比如误配了-XX:+UseG1GC)
G1的STW时间为什么难拆解?
G1的停顿分散在多个环节:Young GC、Mixed GC、Humongous分配失败、Full GC。默认日志里Pause Young或Pause Mixed代表整次GC的STW总耗时,无法分离出“仅扫描根集”或“仅转移对象”的子阶段。
- 想定位瓶颈,得加
-Xlog:safepoint,看safepoint达成延迟是否远高于GC本身耗时——很多“长停顿”其实是业务线程卡在native调用或长循环里,根本没进safepoint -
-XX:+PrintGCApplicationStoppedTime能打印所有JVM停顿(含非GC原因),适合做兜底排查,但无法区分来源 - G1下
MaxGCPauseMillis是软目标,设太低(如20ms)反而引发更频繁GC,增加总体压力
监控STW的核心指标与陷阱
真实STW时间必须从GC日志中结构化解析,不能靠Prometheus直接抓MXBean里的平均值——因为MXBean只暴露汇总统计,丢失单次分布和异常尖峰。
- 重点关注P95/P99单次STW时长,而非平均值;一次200ms停顿对交易系统的影响远超十次20ms
- ZGC典型
PauseInitialMark为0.5–3ms,G1的Pause Young常在20–80ms波动,二者数值不可直接对比——ZGC的停顿只扫根集,G1的停顿包含复制+整理 - 真正决定
PauseInitialMark耗时的是根集大小(static字段、JNI全局引用、线程栈等),不是堆总容量;减少静态集合、避免深度ThreadLocal链比调大堆更有效
不同场景下的STW容忍阈值
停顿是否“超标”,取决于业务语义,不是越小越好——要匹配SLA,也要权衡资源开销。
- Web后端接口:P99 STW ≤100ms 用户基本无感
- 普通撮合引擎:要求≤10ms,否则影响订单处理节奏
- 高频策略系统:需控制在100微秒以内,否则可能错过行情窗口
- 后台批处理任务:可接受数百毫秒停顿,优先保障吞吐量

















