直接看gc日志中“pause”字段或“stopped:”行即可准确获知每次stw真实时长,如[gc pause (young), 0.0421874 secs]中的秒数或stopped: 0.0423456s,它代表所有应用线程被强制暂停的毫秒数,而非gc总耗时。

直接看 GC 日志里的 Pause 字段,就能准确知道每次 STW 的真实持续时间——它不是 GC 总耗时,而是所有应用线程被强制暂停的毫秒数。
抓准日志里真正的 STW 时间字段
启用带完整标记的 GC 日志(如 -Xlog:gc*,safepoint:uptime,time,level,tags 或旧版 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime),重点关注三类明确标出停顿的行:
-
“Pause”开头的记录:例如
[GC pause (G1 Evacuation Pause) (young), 0.0421874 secs],括号里的秒数就是 STW 实际时长; -
“stopped:” 行:由
-XX:+PrintGCApplicationStoppedTime输出,格式如Stopped: 0.0423456s,这是最权威的 STW 测量值; -
对比 user/sys/real 时间:若
real ≈ user + sys,说明停顿基本在 JVM 内部;若real 显著大于二者之和,可能卡在 OS 层(如磁盘写 GC 日志、锁竞争、安全点等待)。
区分不同 GC 类型对应的 STW 特征
不是所有 GC 都产生同等程度的停顿。同一份日志中要按类型归类分析:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- G1 的 Young/Mixed Pause:单次通常 50ms,说明年轻代过小、对象晋升快或跨代引用多;
-
G1 的 Full GC:日志中标为
Full GC,STW 往往几百毫秒到几秒,是严重信号,需立即排查元空间满、大对象直入老年代或并发标记失败; -
ZGC/Shenandoah 的 Initial Mark / Final Mark:虽标称亚毫秒,但若日志中
Thread Root Processing或safepoint耗时突增,说明线程卡在计算、IO 或 JNI 中无法及时进入安全点; -
CMS 的 Concurrent Mode Failure:会退化为 Serial GC 式 Full GC,STW 极长,日志中会明确提示
concurrent mode failure。
把 STW 时间和业务现象对齐验证
单看数字容易误判。必须将日志时间戳与监控系统、链路追踪或用户反馈对齐:
- 查某次接口超时(比如 9:23:15 响应延迟 >2s),立刻翻该时刻前后 ±5 秒的 GC 日志,确认是否有
stopped: 0.812s记录; - 发现 STW 集中在每小时整点,检查是否有人调用
System.gc()或定时任务触发大量对象生成; - 观察 STW 持续时间是否随堆大小线性增长:如果 -Xmx 从 4g 升到 8g 后,Initial Mark 从 0.1ms 涨到 0.6ms,说明根扫描压力变大,需优化线程数或对象图结构。
警惕非 GC 引起的“假 STW”
有些停顿看似来自 GC,实则另有隐情:
-
安全点等待(Safepoint timeout):日志中出现
safepoint相关条目,且stopped:时间远大于对应 GC 的Pause时间,说明有线程卡在长时间 native 调用、循环计算或 synchronized 块中; -
元空间或 CodeCache 耗尽:日志中出现
Metadata GC Threshold或CodeCache is full,也会触发全局 STW; -
GC 日志写入阻塞:尤其在机械硬盘或高 IO 压力下,
write()系统调用可能被 page cache 回写卡住数秒,表现为stopped:很长但user/sys极小——此时应把 gc.log 放到 SSD 或 tmpfs。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










