跳转到内容

诊断工具链

用途:线上出问题(CPU 高、RT 抖、内存涨、线程卡)时按工具组合定位

信息 工具 回答什么
线程栈快照 jstack、kill -3、Arthas thread 线程在等什么、有没有阻塞/死锁
堆快照 jmap -dump、-XX:+HeapDumpOnOutOfMemoryError、Arthas heapdump 谁占着内存、引用链是什么
实时指标 jstat -gcutil、JMX、Prometheus JVM exporter GC 频率、各代使用、线程数趋势
性能剖析 async-profiler(cpu/alloc/lock/native)、JFR、Arthas profiler 时间/分配/锁花在哪一行
  • 宽度 = 占比,不是耗时绝对值;顶层宽就是热点。
  • 分配火焰图(-e alloc) 找分配大户,比事后调 GC 参数有效。
  • 锁火焰图(-e lock) 找等待热点,注意区分“持锁时间长”与“等待时间长”。
  • on-CPU 图平坦说明线程不在计算,多半是阻塞:转去看栈与锁。
  • 内核/框架帧可折叠(--alluser 或过滤),避免噪声掩盖业务栈。

低开销(通常 <1%)的持续事件记录,适合生产常开:

  • jcmd <pid> JFR.start settings=profile name=rec duration=60s filename=/tmp/rec.jfr
  • 事件覆盖:方法采样、GC、 safepoint、内存分配、锁竞争、线程阻塞、IO、类加载。
  • 用 JDK Mission Control 打开分析,重点看 GC 页、方法热点页与锁竞争页。
症状 步骤
CPU 100% top -H 找线程 → 转 16 进制 → 在 jstack 中定位栈;或 async-profiler CPU 图
RT 抖动 GC 日志 + 安全点日志 → 看停顿是否与应用毛刺对齐;再看锁图与下游 RT
内存持续上涨 jstat 看老年代基线 → dump → MAT 支配树(Dominator Tree)找大头
频繁 Full GC GC 日志看触发原因(Metadata GC Threshold / Allocation Failure / Humongous)→ 对应处理
线程堆积 jstack 多次采样对比,看 WAITING/BLOCKED 分布与共同等待对象
堆外内存涨 NMT jcmd VM.native_memory summary + Netty 池指标
  • jmap -dump:live 会触发 Full GC 并造成秒级停顿,大堆慎用,优先用 OOM 自动 dump 或低峰执行。
  • jstack 相对安全,但多次采样间隔要短(1-2 秒)以捕捉变化。
  • Arthas 的 watch/trace 有字节码增强开销,用完 reset;线上禁止长时间 trace 高频方法。
  • 所有诊断产物(dump、jfr)注意脱敏与访问控制,堆 dump 含明文敏感数据。
误区 修正
只看一次线程栈下结论 多次采样看趋势
用 top 的进程 CPU 判断 Java 热点 需要线程级 + 栈符号对齐
有 dump 就等于会分析 必须看支配树与 GC Root 引用链,而不是搜类名
火焰图有帧就认为慢 宽度才是占比,采样噪声要复测
生产常开高开销探针 用 JFR/采样型工具,控制开销预算
  • OpenJDK 工具文档(jcmd、jstat、jmap、jstack、JFR)
  • Arthas 官方文档(诊断命令与实战案例)
  • async-profiler 官方 README(事件类型与用法)