📌 PDF :大白话说Java面试题 --- 02-JVM篇
第28题:对于 JDK 自带的监控和性能分析工具用过哪些?一般你怎么用的
📚 回答:
- 核心考点 :
大厂面试要求熟练掌握 JDK 自带工具 ,并能结合场景说明使用时机、命令参数、结果解读。不能只会罗列工具名称。
1. 工具全景图
| 工具 | 核心用途 | 是否需要目标进程 | 是否STW |
|---|---|---|---|
jps |
列出 Java 进程 PID | 是 | 否 |
jinfo |
查看/修改 JVM 参数 | 是 | 否 |
jstat |
GC 和内存区域实时统计 | 是 | 否 |
jmap |
堆内存快照(dump) | 是 | 是(严重) |
jstack |
线程堆栈快照 | 是 | 否(但可能略慢) |
jcmd |
多功能综合工具(JDK 7+) | 是 | 部分操作会 |
VisualVM |
图形化综合监控 | 是(可本地/远程) | 采样模式不影响 |
2. 各工具典型用法(附命令)
2.1 jps:定位目标进程
bash
jps -l # 显示完整主类名
jps -v # 显示传递给 JVM 的参数
场景:启动分析前第一步,拿到 PID。
2.2 jstat:实时监控 GC(最常用)
bash
# 每1秒打印一次,共打印10次
jstat -gcutil <PID> 1000 10
# 输出列解读:
# S0/S1: Survivor 使用率
# E: Eden 使用率
# O: 老年代使用率
# M: 元空间使用率
# YGC/YGCT: Young GC 次数/总耗时
# FGC/FGCT: Full GC 次数/总耗时
# GCT: GC 总耗时
实战判断:
YGC每分钟超过60次 → 年轻代太小FGC每小时 >1 次 → 需排查(除非元空间/堆合理调优后仍存)GCT / 运行时长> 10% → GC 已严重影响吞吐
2.3 jmap:堆内存快照(谨慎使用)
bash
# 生成 dump 文件(会触发 Full GC,生产需低峰期)
jmap -dump:live,format=b,file=/tmp/heap.hprof <PID>
# 查看对象统计(不会 dump 大文件,但仍会 STW)
jmap -histo:live <PID> | head -30
⚠️ 重要:
-dump:live会先触发 Full GC,STW 时间可能达数秒甚至分钟- 生产环境优先用
-XX:+HeapDumpOnOutOfMemoryError自动 dump - 高并发系统用
jcmd <PID> GC.heap_dump /path/dump.hprof(底层同 jmap,依然 STW)
分析 dump :用 MAT(Eclipse Memory Analyzer) 或 VisualVM 查看 Leak Suspects、Dominator Tree。
2.4 jstack:线程快照(无痛)
bash
# 导出线程栈
jstack -l <PID> > thread.dump
# 快速统计线程状态
grep "java.lang.Thread.State" thread.dump | sort | uniq -c
经典用法:
- CPU 飙高 :
top -H -p <PID>找线程 ID(十进制的) →printf "%x\n" <十进制tid>→ 在 jstack 输出中搜索十六进制 tid - 死锁 :jstack 输出末尾会直接报告 "Found one Java-level deadlock"
- 接口超时:连续多次打印 jstack,对比 WAITING/BLOCKED 线程是否一直卡在同一位置
2.5 jinfo:查看运行时参数
bash
# 查看所有可设置参数及当前值
jinfo -flags <PID>
# 查看单个参数
jinfo -flag UseG1GC <PID>
# 动态修改(部分参数支持)
jinfo -flag +HeapDumpOnOutOfMemoryError <PID>
场景 :线上验证 -Xmx 是否生效、某个 GC 参数是否真的被打开。
2.6 jcmd:新一代瑞士军刀(JDK 7+ 推荐)
bash
# 列出所有可执行命令
jcmd <PID> help
# 查看 JVM 运行时参数(替代 jinfo -flags)
jcmd <PID> VM.flags
# 手动触发 GC(慎用,仅测试)
jcmd <PID> GC.run
# 获取系统属性
jcmd <PID> VM.system_properties
# 获取线程栈(同 jstack)
jcmd <PID> Thread.print
# 生成 heap dump
jcmd <PID> GC.heap_dump /tmp/dump.hprof
# 查看 Native 内存(诊断直接内存/堆外)
jcmd <PID> VM.native_memory summary
优势:统一入口,输出结构更清晰,部分操作比 jmap 更安全。
2.7 VisualVM:图形化利器
连接方式:
- 本地:自动检测本机 Java 进程
- 远程 :通过 JMX(需开启
-Dcom.sun.management.jmxremote)
常用 Tab:
- Monitor:CPU/堆/元空间/类/线程 实时曲线
- Threads:线程状态及堆栈,可检测死锁
- Sampler:CPU 采样 → 热点方法;内存采样 → 对象分配统计
- Profiler(需插件):更精确但开销大,生产慎用
生产远程连接示例(JMX 参数):
bash
-Dcom.sun.management.jmxremote=true \
-Dcom.sun.management.jmxremote.port=9999 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false
3. 实战案例:生产 Full GC 频繁排查
现象 :服务 GC 报警,FGC 每小时 12 次,老年代占用率 95% 不降。
步骤:
| 步骤 | 工具 | 命令 | 发现 |
|---|---|---|---|
| 1 | jps |
jps -l |
PID 12345 |
| 2 | jstat |
jstat -gcutil 12345 1000 |
O(老年代)始终 98%,FGC 持续增长 |
| 3 | jmap(低峰期) |
`jmap -histo:live 12345 | head -20` |
| 4 | jstack |
jstack 12345 > t.dump |
大量线程在 SessionCache.put 等待锁 |
| 5 | 定位代码 | 结合业务日志 | 缓存未设过期时间,且未限制最大容量 |
| 6 | 修复 | 代码:改用 Caffeine 缓存 + TTL |
上线后 FGC 降为 0 |
4. 面试官追问示例
Q1:jmap -histo:live 会触发 Full GC 吗?
A:会 。live 参数会先执行一次 Full GC 再统计存活对象。生产环境慎用,优先用 jstat 看趋势或 Arthas heapdump。
Q2:jstack 打印出的 BLOCKED 线程很多,一定有问题吗?
A:不一定。若 BLOCKED 是瞬时锁竞争且正常情况(如 synchronized 高并发),只要不持续堆积就正常。需多次打印确认是否一直卡在同一锁。
Q3:远程连接 VisualVM 不安全怎么办?
A:生产禁止明文 JMX。替代方案:
- 用
jstat/jstack本地执行后导出分析 - 用 Arthas(阿里开源)隧道连接
- 开启 JMX + SSL 认证(复杂)
Q4:jcmd 能完全替代 jmap 吗?
A:大部分可以。jcmd GC.heap_dump 同 jmap -dump,但 jcmd VM.native_memory 是 jmap 没有的功能。不过 jmap -histo 的快速对象统计,jcmd 没有直接等价命令。
Q5:生产环境不能安装任何额外工具,只有 JDK 自带,怎么排查?
A:就用 jps/jstat/jstack/jmap/jcmd 组合。例如:
- CPU 高 →
top -H -p PID+jstack - 内存泄漏 →
jstat -gcutil看 O 区持续增长 +jmap -dump:live(择低峰期) - GC 频繁 →
jstat -gc看明细
💡 面试官想要的满分总结:
"日常问题排查,我按以下组合使用:
- jps 找 PID
- jstat -gcutil 看 GC 趋势,决定是否需要 dump
- jstack 查线程阻塞/死锁/热点栈
- jmap 只在低峰期或 OOM 后分析 dump
- jcmd 作为统一入口,尤其 VM.native_memory 排查堆外内存
- VisualVM 用于本地或开发环境做性能分析
核心原则:生产环境首选无侵入工具(jstat/jstack/jcmd 非 live 操作),jmap 务必审批后执行。"
觉得对您有帮助,麻烦 点点关注啦 ,您的关注是我创作的最大动力~ 🎯