05-JVM 监控与故障排查工具

JVM 监控与故障排查工具

一、命令行工具(JDK 自带)

1.1 jps(Java Process Status)

查看 Java 进程。

bash 复制代码
jps -l          # 显示完整类名
jps -v          # 显示 JVM 参数
jps -m          # 显示 main 方法参数

# 输出示例
12345 com.example.MyApp
12346 org.apache.catalina.startup.Bootstrap

1.2 jstat(JVM Statistics Monitoring Tool)

监控 JVM 统计信息。

bash 复制代码
# 查看 GC 情况
jstat -gc <pid> 1000 10    # 每秒输出一次,共 10 次

# 输出字段
S0C/S1C     # Survivor 区容量
S0U/S1U     # Survivor 区使用量
EC/EU       # Eden 区容量/使用量
OC/OU       # 老年代容量/使用量
MC/MU       # 元空间容量/使用量
YGC/YGCT    # Young GC 次数/时间
FGC/FGCT    # Full GC 次数/时间
GCT         # 总 GC 时间

# 查看类加载
jstat -class <pid>

# 查看编译
jstat -compiler <pid>

1.3 jinfo(Configuration Info)

查看和修改 JVM 配置。

bash 复制代码
# 查看所有参数
jinfo <pid>

# 查看特定参数
jinfo -flag MaxHeapSize <pid>

# 动态修改参数(部分参数支持)
jinfo -flag +PrintGCDetails <pid>

1.4 jmap(Memory Map)

生成堆转储快照。

bash 复制代码
# 查看堆使用情况
jmap -heap <pid>

# 查看对象分布
jmap -histo <pid> | head -20

# 生成 Heap Dump
jmap -dump:format=b,file=heap.hprof <pid>

# 生成时压缩
jmap -dump:live,format=b,file=heap.hprof <pid>

1.5 jstack(Stack Trace)

生成线程转储快照。

bash 复制代码
# 查看所有线程
jstack <pid>

# 查找死锁
jstack <pid> | grep -A 20 "deadlock"

# 导出到文件
jstack <pid> > thread_dump.txt

# 查看 native 栈
jstack -m <pid>

线程状态

  • RUNNABLE:运行中或可运行
  • BLOCKED:等待获取锁
  • WAITING:无限期等待(wait() / park()
  • TIMED_WAITING:限时等待(sleep() / wait(timeout)

1.6 jcmd(Diagnostic Command)

综合诊断工具(JDK 7+)。

bash 复制代码
# 列出所有诊断命令
jcmd <pid> help

# 查看堆信息
jcmd <pid> GC.heap_info

# 触发 GC
jcmd <pid> GC.run

# 生成 Heap Dump
jcmd <pid> GC.heap_dump /path/to/heap.hprof

# 查看线程
jcmd <pid> Thread.print

# 查看类加载
jcmd <pid> VM.class_hierarchy

二、可视化工具

2.1 JConsole

JDK 自带的图形化监控工具。

bash 复制代码
jconsole

功能

  • 内存监控(堆、非堆)
  • 线程监控(死锁检测)
  • 类加载监控
  • MBean 管理

2.2 VisualVM

更强大的图形化工具(JDK 8 内置,JDK 11+ 需单独下载)。

功能

  • 实时监控(CPU、内存、线程、类)
  • 性能分析(CPU Profiler、Memory Profiler)
  • Heap Dump 分析
  • Thread Dump 分析
  • MBean 浏览器

2.3 MAT(Memory Analyzer Tool)

Eclipse 提供的内存分析工具。

下载地址www.eclipse.org/mat/

功能

  • 分析 Heap Dump
  • 查找内存泄漏
  • Dominator Tree(支配树)
  • Histogram(直方图)
  • OQL(对象查询语言)

使用步骤

  1. 打开 .hprof 文件
  2. 查看 Leak Suspects Report(自动分析泄漏嫌疑)
  3. 使用 Dominator Tree 查找大对象
  4. 分析引用链,找到泄漏源头

2.4 Arthas(阿里开源)

线上诊断神器。

下载地址arthas.aliyun.com/

启动

bash 复制代码
java -jar arthas-boot.jar

常用命令

bash 复制代码
# 查看 dashboard
dashboard

# 监控方法调用
monitor com.example.MyClass myMethod

# 追踪方法调用链路
trace com.example.MyClass myMethod

# 查看方法参数和返回值
watch com.example.MyClass myMethod '{params, returnObj}'

# 热更新代码
redefine /path/to/MyClass.class

# 查看线程
thread
thread -b          # 查找阻塞其他线程的线程

# 查看 JVM 信息
vmoption
sysprop
sysenv

三、常见故障排查

3.1 CPU 飙高

排查步骤

bash 复制代码
# 1. 找到 CPU 高的 Java 进程
top

# 2. 查看进程中 CPU 高的线程
top -H -p <pid>

# 3. 将线程 ID 转换为 16 进制
printf "%x\n" <tid>

# 4. 查看线程栈
jstack <pid> | grep <16进制tid> -A 20

# 5. 分析代码,找出死循环或频繁计算

3.2 内存泄漏

排查步骤

bash 复制代码
# 1. 监控堆内存趋势
jstat -gc <pid> 1000

# 2. OOM 时生成 Heap Dump
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/heap.hprof

# 3. 手动生成 Dump
jmap -dump:live,format=b,file=heap.hprof <pid>

# 4. 用 MAT 分析
#    - 查看 Dominator Tree
#    - 查找占用内存最多的对象
#    - 分析引用链

3.3 死锁

排查步骤

bash 复制代码
# 1. 生成线程转储
jstack <pid> > thread_dump.txt

# 2. 查找死锁信息
grep -A 20 "deadlock" thread_dump.txt

# 3. 或者用 JConsole / VisualVM 的死锁检测功能

# 4. 分析持锁关系,修复代码

死锁示例输出

vbnet 复制代码
Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f... (object 0x000000..., a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f... (object 0x000000..., a java.lang.Object),
  which is held by "Thread-1"

3.4 Full GC 频繁

排查步骤

bash 复制代码
# 1. 查看 GC 日志
jstat -gc <pid> 1000

# 2. 分析 GC 原因
#    - 老年代满?→ 增大堆或优化对象生命周期
#    - 元空间满?→ 增大 Metaspace
#    - System.gc()?→ 检查代码或添加 -XX:+DisableExplicitGC

# 3. 生成 Heap Dump 分析
jmap -dump:live,format=b,file=heap.hprof <pid>

# 4. 优化建议
#    - 减少大对象创建
#    - 对象池复用
#    - 调整新生代大小

3.5 线程数过多

排查步骤

bash 复制代码
# 1. 查看线程数
jstack <pid> | grep "java.lang.Thread.State" | wc -l

# 2. 查看线程详情
jstack <pid> > thread_dump.txt

# 3. 分析线程类型
#    - 业务线程过多?→ 检查线程池配置
#    - WAITING 线程过多?→ 检查是否有资源等待
#    - BLOCKED 线程过多?→ 检查锁竞争

# 4. 优化建议
#    - 使用线程池
#    - 减少锁粒度
#    - 异步化处理

四、Arthas 实战案例

4.1 定位慢方法

bash 复制代码
# 追踪方法执行时间
trace com.example.OrderService createOrder

# 输出示例
`---ts=2024-01-01 12:00:00;thread_name=http-nio-8080-exec-1;id=1a;is_daemon=true;priority=5;
    `---[0.523ms] com.example.OrderService:createOrder()
        +---[0.012ms] validateOrder()
        +---[0.456ms] saveToDatabase()  ← 慢
        `---[0.055ms] sendNotification()

4.2 查看方法入参和返回值

bash 复制代码
# 监控方法调用
watch com.example.UserService getUser '{params, returnObj}' -x 2

# 输出示例
method=com.example.UserService.getUser location=AtExit
ts=2024-01-01 12:00:00; [cost=0.234ms]
param[0]=12345
return=@User[id=12345,name=Alice,email=alice@example.com]

4.3 热更新代码(紧急修复 Bug)

bash 复制代码
# 1. 编译新代码
javac -cp app.jar MyClass.java

# 2. 上传到服务器

# 3. 热更新
redefine /path/to/MyClass.class

# 4. 验证

注意:只能修改方法体,不能修改方法签名、字段、继承关系。


4.4 查看系统属性

bash 复制代码
# 查看 JVM 参数
vmoption

# 查看系统属性
sysprop

# 查看环境变量
sysenv

五、面试题精选

Q1:如何排查 CPU 飙高问题?

  1. top 找到 CPU 高的进程
  2. top -H -p <pid> 找到 CPU 高的线程
  3. printf "%x" 转换线程 ID 为 16 进制
  4. jstack 查看线程栈
  5. 分析代码,找出死循环或频繁计算

Q2:如何排查内存泄漏?

  1. 监控堆内存趋势(持续增长)
  2. OOM 时生成 Heap Dump
  3. 用 MAT 分析,查找大对象和引用链
  4. 定位泄漏代码,修复

Q3:jstack 和 jmap 的区别?

  • jstack:生成线程转储,查看线程状态、死锁
  • jmap:生成堆转储,查看对象分布、内存泄漏

Q4:什么是 Heap Dump 和 Thread Dump?

  • Heap Dump:堆内存快照,包含所有对象信息,用于分析内存泄漏
  • Thread Dump:线程快照,包含所有线程状态和栈信息,用于分析死锁、CPU 高

Q5:Arthas 的优势是什么?

  1. 无需重启应用
  2. 支持线上诊断
  3. 功能强大(监控、追踪、热更新)
  4. 非侵入式

Q6:Full GC 频繁怎么排查?

  1. 查看 GC 日志,确认 GC 原因
  2. 生成 Heap Dump 分析
  3. 检查是否有内存泄漏
  4. 调整堆大小或 GC 参数
  5. 优化代码,减少对象创建

Q7:如何预防死锁?

  1. 固定锁顺序
  2. 使用 tryLock 超时
  3. 减少锁粒度
  4. 使用 jstack 定期检测

Q8:生产环境如何监控 JVM?

  1. 命令行工具jstatjmapjstack
  2. 可视化工具:VisualVM、MAT
  3. APM 工具:Arthas、SkyWalking、Pinpoint
  4. 日志监控:GC 日志、应用日志
  5. 指标监控:Prometheus + Grafana
相关推荐
geovindu1 小时前
CSharp: Task Scheduler
开发语言·后端·c#·.net·.netcore
Zane19941 小时前
两个线程算两遍循环,为什么只快了一点点不是两倍?GIL连环追问
后端·python
只爱喝胡辣汤2 小时前
04-JVM 性能调优参数
后端
Bs_MoneyMagnet2 小时前
基于springboot+vue的家居生活商城平台的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring
爱勇宝2 小时前
《道德经》第 11 章:真正有用的,常常是你没写出来的那部分
前端·后端·产品
微三云 - 廖会灵 (私域系统开发)2 小时前
Spring Boot实战:五级分销定价与自动分佣系统设计与实现
java·spring boot·后端
钱栈up2 小时前
mvn compile卡住半小时:定位并修复隐藏的类型不匹配编译错误
java·后端·maven
妙码生花2 小时前
golang 应用服务端部署(使用 systemd 服务)
开发语言·人工智能·后端·golang·node.js·php·gin
Zane19942 小时前
Lambda表达式没有类型,为什么还能被当成参数传来传去
java·后端