JVM调优工具实战

§2.1.5 JVM调优工具实战

考察意图:能否独立的在生产环境排查问题,使用合适的工具定位根因。

回答样板

Arthas——线上诊断神器

阿里开源的Java诊断工具,零侵入,直接attach到运行中的Java进程,线上排查首选。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 启动
java -jar arthas-boot.jar
# 选择目标Java进程即可

# 最常用命令
dashboard                           # 实时看板:线程/内存/GC/CPU
thread -n 5                         # CPU最高的5个线程
thread -b                           # 找出死锁
jad com.xx.MyService                # 反编译已加载的类,验证线上版本
watch com.xx.MyService myMethod "{params,returnObj,throwExp}" -x 3  # 监控方法入参/出参/异常
trace com.xx.MyService myMethod -n 5  # 追踪方法调用链路,找出哪个子步骤耗时最长
tt -t com.xx.MyService myMethod       # 记录方法调用(TimeTunnel),支持重放
vmoption                            # 查看JVM参数
vmtool --action getInstances -c com.xx.MyClass --limit 10  # 获取堆中某类实例
monitor -c 5 com.xx.MyService myMethod  # 监控方法调用次数/成功率/平均耗时

实际场景:一次线上接口变慢,用Arthas的trace一追踪,发现是下游规则引擎的Drools session创建占了80%耗时——KieSession没做池化每次new一个。加了KieSession对象池后恢复。

JDK自带工具——四件套

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# jps —— 列出Java进程
jps -lv             # 列出所有Java进程,显示JVM参数和main类

# jstat —— JVM统计监控(实时看GC)
jstat -gcutil PID 1000 10   # 每秒打印一次GC统计,共10次
# 输出关键列:S0/S1(Eden+Survivor使用率), E(eden), O(old), M(metaspace), YGC/YGCT(youngGC次数/耗时), FGC/FGCT(fullGC)
# 解读:FGC频繁 + FGCT高 → 老年代不足或内存泄漏
#       E接近100%然后骤降 → 正常Minor GC
#       O持续增长不降 → 内存泄漏信号

# jmap —— 堆内存分析
jmap -heap PID                          # 堆内存概览(各区域大小和使用率)
jmap -histo:live PID | head -20         # 堆中存活对象统计(top 20,强制执行一次Full GC)
jmap -dump:format=b,file=heap.hprof PID # 堆dump(生产慎用,会STW)

# jstack —— 线程堆栈分析
jstack PID > thread.log                 # 打印线程堆栈
jstack -l PID                           # 额外打印锁信息
# grep查找:BLOCKED(锁等待)/ WAITING(等待唤醒)/ TIMED_WAITING(超时等待)/ RUNNABLE(正在执行)
# 看线程名:如果全是http-nio-xxx-WAITING → 数据库或下游服务慢

MAT(Memory Analyzer Tool)——堆dump分析

1
2
3
4
5
6
# 先用 jmap dump 堆快照,然后用MAT打开分析
# MAT直接点"Leak Suspects Report" → 自动分析内存泄漏嫌疑
# 核心操作:
#   1. Histogram:按类统计对象数量和内存占用,找大对象
#   2. Dominator Tree:支配树——最大的内存持有者
#   3. Path to GC Roots:某个对象为什么没被回收(引用链追溯到GC Root)

实际场景:OOM排查,MAT打开dump→ Dominator Tree发现HashMap占3.2GB→ Path to GC Roots找到是定时任务的全量缓存→改成分页+本地缓存解决。

jinfo——查看/修改JVM运行时参数

1
2
jinfo -flags PID         # 查看所有参数(包括默认值)
jinfo -flag +PrintGC PID # 运行时动态开启GC日志(部分参数支持动态修改)

生产环境排查最佳路径

  1. 遇到CPU飙升 → Arthas dashboard + thread -n 5 → 定位到具体线程 → jad反编译验证 → 改代码
  2. 遇到内存泄漏 → jstat -gcutil观察O区持续增长 → jmap -dump → MAT分析Dominator Tree → Path to GC Roots → 改代码
  3. 遇到死锁 → jstack -l → 搜DEADLOCK → 或Arthas thread -b
  4. 遇到接口变慢 → Arthas trace → 定位最耗时的子调用 → 深入分析

陷阱提示:只会用jps/jstat但说不清每列含义;线上 jmap -dump不提醒STW风险;不知道Arthas的attach机制(VirtualMachine.attach不需要Agent)。

本作品采用 CC BY-NC-SA 4.0 协议进行许可
使用 Hugo 构建
主题 StackJimmy 设计