← 返回题目列表

JVM 线上问题排查常用哪些工具?

高频 中等 第 8 / 34 题 更新于 2026/07/25
JVM排查工具jstackjmap

简化版

一套 JDK 自带命令行工具够用大半:jps(看有哪些 Java 进程)、jstat(看 GC 和内存实时统计)、jstack(打线程栈,查死锁/CPU 高)、jmap(导堆快照 heap dump)、jinfo(看/改参数)。分析 dump 用 MATJProfiler;一站式在线诊断用阿里 Arthas。核心思路:先定位是什么问题(CPU/内存/GC/线程),再选对应工具抓现场。

详细版

JDK 自带命令行工具(面试常考)

工具作用典型场景
jps列出 Java 进程和 PID先找到目标进程
jstat实时看 GC 次数/耗时、各代内存判断是否频繁 GC、内存涨势
jstack打印线程堆栈快照CPU 飙高、死锁、线程卡住
jmap导出堆内存快照(heap dump)内存泄漏、OOM 分析
jinfo查看/动态调整 JVM 参数确认运行参数

图形化 / 分析工具

  • MAT(Memory Analyzer Tool):分析 heap dump,找最大对象、GC Root 引用链、内存泄漏嫌疑。
  • VisualVM / JConsole:可视化监控内存、线程、GC。
  • Arthas(阿里开源):线上诊断神器,不用重启就能看方法耗时、调用栈、热更新,功能最全。

完整版教学

一、排查的正确顺序:先分类,再抓现场

面试官问这题,想听的是排查思路,不是工具名罗列。正确套路是「先判断问题类型 → 再用对应工具抓现场 → 分析定位根因」:

  • CPU 高top 找到进程 → jstack 抓线程栈,看哪些线程在狂跑;
  • 内存涨/OOMjstat 看 GC 趋势 → jmap 导 dump → MAT 分析;
  • 频繁 GC / 卡顿jstat -gcutil 看 GC 频率和耗时 → GC 日志定位;
  • 线程卡死/死锁jstack 看线程状态和锁持有。

工具是手段,先有假设再验证才是关键。

二、CPU 100% 怎么查——经典组合拳

这是最高频的实战题,标准流程:

top                          # 1. 找到 CPU 高的 Java 进程 PID
top -Hp <pid>                # 2. 找到该进程里 CPU 高的线程 TID
printf "%x\n" <tid>          # 3. 线程 TID 转成 16 进制(jstack 里是 16 进制的 nid)
jstack <pid> | grep <十六进制tid> -A 30   # 4. 在线程栈里定位到具体代码行

一步步把「哪个进程 → 哪个线程 → 哪行代码」缩小,就能找到是死循环、正则回溯、还是频繁 GC(GC 线程占 CPU)导致的高 CPU。

三、内存泄漏/OOM 怎么查

jmap -dump:live,format=b,file=heap.hprof <pid>   # 导出堆快照
# 或启动时就配好:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=...

拿到 dump 后用 MAT 分析,重点看两个东西:

  • 最大保留集(Retained Heap):谁占的内存最多;
  • GC Root 引用链:这个大对象为什么还没被回收——顺着引用链找到「谁一直握着它不放」,就是泄漏根因(常见是静态集合只增不减、缓存无上限、连接/监听器没释放)。

记忆点:看 dump 不是找「最大的对象」,而是找「它为什么还被 GC Root 引用」。

四、jstat 看 GC——不用重启的实时监控

jstat -gcutil <pid> 1000     # 每 1 秒打印一次各代使用率和 GC 统计

输出里 YGC/YGCT(年轻代 GC 次数/耗时)、FGC/FGCT(Full GC 次数/耗时)最关键。如果 FGC 短时间内快速增长,说明频繁 Full GC,往往是内存泄漏或配置问题的信号(详见「Minor/Major/Full GC 的区别」那道题)。

五、Arthas:线上诊断的瑞士军刀

jstack/jmap 是「抓一次快照」,而 Arthas动态、实时观察运行中的应用而不重启:

  • thread -n 3:看最忙的 3 个线程;
  • trace 类 方法:看某方法内部各步骤耗时,定位慢在哪;
  • watch:观察方法入参/返回值/异常;
  • jad/redefine:反编译、甚至热更新一个类。

它把上面一堆命令的能力整合成交互式界面,是现在线上排查的主流工具,面试能提到很加分。

六、抓现场要评估工具本身的影响

线上诊断不是“命令越多越好”。堆转储文件可能接近已用堆大小,生成过程可能产生明显暂停和磁盘压力;高频采样、跟踪所有方法也会消耗 CPU。

目标优先证据风险控制
CPU 异常多次线程栈、JFR/采样剖析避免只抓一次栈下结论
死锁/阻塞jcmd Thread.printjstack对比锁拥有者和等待者
堆 OOM自动 heap dump、类直方图预留磁盘,控制手工 dump 时机
GC 抖动GC 日志、jstat、JFR统一时间线并关联流量
类加载异常class histogram、类加载统计查类加载器及卸载趋势

例如进程已用堆 8 GB,手工 dump 前至少要确认目标磁盘有足够余量;不要在根分区只剩 2 GB 时直接执行。jcmd 通常是现代 HotSpot 优先的综合入口,但命令能力取决于 JDK 版本,且 attach 需要同用户、权限和容器命名空间等条件。

七、形成可复盘的证据链

一次可靠排查至少保留:故障时间、流量和发布事件、进程/容器资源、连续线程栈、GC 日志、必要的 dump 以及所用 JDK 参数。

CPU 高时连续抓 3 次、间隔数秒的线程栈,比单次快照更能区分“偶然正在运行”和“持续占用”。Linux 线程 ID 转十六进制后匹配 nid 只是 HotSpot 常见流程;容器内 PID 映射和工具版本不一致时应先核实进程视图。

现象确认 → 分类假设 → 低风险证据 → 必要时重证据 → 交叉验证 → 修复与回归

工具输出是证据,不是结论。必须把同一时间窗口的 CPU、线程、GC、流量和发布变化对齐。

八、常见误区与追问

  • 误区:线上卡顿时先重启再慢慢分析。 若业务允许,应先抓低风险现场;紧急恢复和证据留存需要按预案并行权衡。
  • 误区:堆里占用最大的对象就是泄漏源。 大对象可能是合理缓存,关键是增长趋势和到 GC Roots 的保留链。
  • 误区:线程栈只抓一次就能确认 CPU 热点。 单次样本可能恰好命中正常执行,连续样本或采样剖析更可靠。
  • 追问:为什么优先考虑 jcmd 它是现代 HotSpot 支持的综合诊断入口,可查询线程、堆、JFR 等信息,但仍要核对版本命令。
  • 追问:何时用 JFR? 需要低开销持续观察 CPU、锁、分配和 GC 事件时,JFR 往往比侵入式逐方法跟踪更合适。
  • 追问:kill -3 会杀死 Java 进程吗? 在常见 HotSpot/Unix 环境中它发送 SIGQUIT,通常打印线程转储而非终止进程,但仍应按运行环境验证。
  • 追问:OOM 后为什么还要看 GC 日志? 日志能说明是持续高占用、分配突增、元空间压力还是并发回收来不及完成。

九、加强记忆

把排查流程记成“定时间、分类型、轻取证、重验证”:先对齐故障与流量发布事件,再区分 CPU、锁、堆、GC、类加载或本地内存问题。CPU 要看连续线程样本或 JFR,堆问题要看增长趋势与 GC Roots 保留链,GC 问题要看原因和回收前后基线。heap dump、全量跟踪等重操作可能带来暂停与磁盘压力,必须按预案评估后再用。工具输出只是证据,最终结论必须由同一时间线上的多组指标交叉证明。