JVM 性能监控与调优
命令行工具
jps — JVM 进程状态
bash
jps -l # 显示完整主类名
jps -v # 显示 JVM 参数
jps -m # 显示 main 方法参数jstat — 统计信息监视
bash
# 查看类加载
jstat -class <pid> 1000 5
# 查看 GC 统计
jstat -gc <pid> 1000
S0C S1C S0U S1U EC EU OC OU
1024.0 1024.0 512.0 0.0 8192.0 4096.0 65536.0 16384.0
# 查看 GC 详细信息
jstat -gcutil <pid> 1000
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 50.00 65.32 25.12 92.15 90.32 128 2.540 5 1.200 3.740
jstat -gccause <pid> # 显示最近 GC 原因jmap — 内存映射
bash
# 堆直方图(最常用,安全)
jmap -histo <pid>
# 转储堆(生产慎用,会 STW)
jmap -dump:live,format=b,file=heap.hprof <pid>jstack — 线程堆栈
bash
# 导出线程栈
jstack <pid>
# 查看死锁
jstack <pid> | grep -A 30 "Deadlock"
# 查看高 CPU 线程
top -H -p <pid> # 找出高 CPU 线程 nid
printf "%x\n" <nid> # 转十六进制
jstack <pid> | grep -A 30 <nid> # 查看对应线程栈jinfo — 配置信息
bash
jinfo -flags <pid> # 所有 JVM 参数
jinfo -sysprops <pid> # 系统属性
jinfo -flag PrintGCDetails <pid> # 查看单个参数
jinfo -flag +PrintGCDetails <pid> # 动态开启参数jcmd — 综合命令(JDK 7+)
bash
jcmd <pid> help # 获取可用命令
jcmd <pid> VM.flags # 查看 JVM 参数
jcmd <pid> GC.heap_dump /path/heap.hprof # 堆转储
jcmd <pid> Thread.print # 打印线程栈
jcmd <pid> VM.uptime # 运行时间
jcmd <pid> VM.system_properties # 系统属性
jcmd <pid> VM.version # JVM 版本
jcmd <pid> GC.class_histogram # 类直方图可视化工具
VisualVM
JDK 自带的监控工具(JDK 9+ 需单独下载 jvisualvm):
bin/jvisualvm.exe主要功能:
- 实时监控 CPU、堆、Metaspace、线程
- 生成/分析堆转储
- 分析线程 Dump
- 插件扩展(Visual GC)
JConsole
JDK 自带,轻量级:
bin/jconsole.exe功能:概述、内存、线程、类、VM 概要、MBean
Arthas 实战
阿里开源的 Java 诊断工具,无需重启、无需改代码。
安装启动
bash
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
# 选择目标进程后进入交互模式核心命令
watch — 方法调用观测:
bash
# 查看方法参数、返回值、异常
watch com.example.service.UserService getUser '{params,returnObj,throwExp}' -x 2
# 查看方法耗时
watch com.example.service.UserService getUser '#cost>100' -n 5trace — 方法内部调用链:
bash
# 看方法内每步调用的耗时
trace com.example.service.UserService getUser
# 只看超过 100ms 的
trace com.example.service.UserService getUser '#cost>100'stack — 查看方法调用栈:
bash
stack com.example.service.UserService getUsermonitor — 方法调用统计:
bash
monitor com.example.service.UserService getUser -c 5tt — 时空隧道(方法执行数据录制):
bash
tt -t com.example.service.UserService getUser
tt -l # 列出录制记录
tt -i 1000 -p # 重放ognl — 执行任意表达式:
bash
# 获取静态字段
ognl '@com.example.Config@TIMEOUT'
# 调用 Bean 方法
ognl '#ctx=@com.example.SpringContext@getBean("userService"),#ctx.getUser(1)'
# 查看 Map 内容
ognl '@java.lang.System@getProperties().get("java.version")'其他常用命令:
| 命令 | 用途 |
|---|---|
dashboard | 仪表盘:CPU、内存、GC、线程 |
thread | 查看线程状态、堆栈 |
jvm | 查看 JVM 信息 |
memory | 各区域内存使用 |
sc/sm | 查看/搜索类/方法 |
heapdump | 生成堆转储 |
jad | 反编译类 |
mc/redefine | 热替换代码 |
logger | 动态调整日志级别 |
MAT 堆分析
生成堆转储
bash
# 方式 1:jmap
jmap -dump:live,format=b,file=heap.hprof <pid>
# 方式 2:jcmd
jcmd <pid> GC.heap_dump heap.hprof
# 方式 3:Arthas
heapdump heap.hprof
# 方式 4:JVM 自动转储
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/dump/分析关键指标
| 指标 | 说明 |
|---|---|
| GC Roots | 根引用路径 |
| Dominator Tree | 支配树,找大对象 |
| Accumulated Objects | 保留集,排内存泄漏 |
| OQL | 对象查询语言 |
OQL 示例
sql
-- 查询所有字符串长度为 0 的 String
SELECT * FROM java.lang.String s WHERE s.value.length = 0
-- 查询所有 byte[] 按大小降序
SELECT * FROM byte[] ORDER BY length DESC
-- 查询所有 Thread 对象
SELECT * FROM java.lang.Thread
-- 查询特定类的实例
SELECT * FROM com.example.MyLeakyClass常见分析模式
对象保留大小 = 对象本身 + 被其持有的其他对象
浅大小 = 对象本身(不含引用对象)
可疑泄漏 → 保留集大的对象 → Dominator Tree 找 GC RootOOM 排查
堆溢出(Java heap space)
原因:对象无法回收或创建过多
排查步骤:
bash
1. jstat -gcutil <pid> 1s # 确认老年代持续增长
2. jmap -histo <pid> # 目标类
3. 转储堆 → MAT 分析 # Dominator Tree 找大对象
4. 代码层面检查:循环创建对象、数据库/文件未关闭、ThreadLocal 未 remove栈溢出(StackOverflowError)
原因:递归过深或线程栈过小
排查:
bash
jstack <pid> # 查看循环调用的线程解决:检查递归、增大 -Xss
元空间溢出(Metaspace)
原因:类加载过多(频繁热部署、CGLib 代理)
排查:
bash
jstat -gcutil <pid> # 看 M 列
jcmd <pid> GC.class_stats # 类统计解决:
- 增大
-XX:MaxMetaspaceSize - 检查 CGLib/Proxy 使用
- 热部署后卸载类
直接内存溢出
原因:NIO DirectBuffer 未释放
排查:
bash
-XX:MaxDirectMemorySize # 限制直接内存大小
pmap <pid> # 查看进程内存映射解决:检查 NIO 使用,确保 Buffer 释放
性能调优指标
目标
吞吐量 = 用户代码执行时间 / (用户代码 + GC 时间)
响应时间 = 暂停时间 (STW)| 场景 | 优先 | 典型配置 |
|---|---|---|
| 批处理/大数据 | 吞吐量 | Parallel GC |
| Web/微服务 | 低停顿 | G1 / ZGC |
| 实时系统 | 极低停顿 | ZGC / Shenandoah |
调优流程
1. 明确目标(吞吐量?响应时间?)
2. 收集基准数据(GC 日志、CPU、内存、RT)
3. 确定瓶颈(GC 频繁?内存不够?代码低效?)
4. 调整配置(堆大小、GC 类型、参数)
5. 验证效果(对比基准)
6. 持续监控关键参数速查
-Xms -Xmx # 堆大小(设相同值避免动态调整)
-Xmn # 新生代
-XX:MetaspaceSize # 元空间
-XX:MaxDirectMemorySize # 直接内存
-XX:+PrintGCDetails # GC 日志
-XX:+HeapDumpOnOutOfMemoryError # OOM 自动转储
-XX:MaxGCPauseMillis=100 # G1 停顿目标
-XX:ParallelGCThreads=4 # 并行 GC 线程
-XX:ConcGCThreads=2 # 并发 GC 线程