Java性能分析工具使用
性能分析工具帮助定位CPU、内存、线程等问题,是调优的必备技能。
工具分类
| 类型 | 工具 | 用途 |
|---|---|---|
| JDK内置 | jstat, jmap, jstack | 基础监控 |
| 可视化 | JConsole, VisualVM | 实时监控 |
| 分析工具 | MAT, JProfiler | 内存/性能分析 |
| 线上诊断 | Arthas, BTrace | 无需重启诊断 |
| APM | SkyWalking, Pinpoint | 分布式链路追踪 |
VisualVM
功能概述
- 监控CPU、内存、线程
- 分析堆内存快照
- 分析CPU性能采样
- 插件扩展(VisualGC)
使用方法
Bash
# 启动
jvisualvm
# 或命令行
jvisualvm --openpid <pid>
监控面板
Java
┌─────────────────────────────────────┐
│ VisualVM监控 │
├─────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ │
│ │ CPU监控 │ │ 内存监控 │ │
│ │ 利用率曲线 │ │ 堆/非堆曲线 │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────────────────────┐ │
│ │ 纚程监控 │ │
│ │ 纚程数、状态、线程列表 │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
抽样分析
Bash
// CPU抽样:找出热点方法
// 内存抽样:找出对象数量和大小
JProfiler
功能特点
- CPU热点分析
- 内存分配追踪
- 线程状态监控
- 数据库SQL追踪
- 远程连接
使用配置
Bash
# 启动参数
-agentpath:/path/to/jprofiler/bin/linux-x64/libjprofilerti.so=port=8849
# 本地连接
直接启动JProfiler GUI
CPU热点分析
Bash
┌─────────────────────────────────────┐
│ CPU热点方法排名 │
├─────────────────────────────────────┤
│ 方法 │ 时间占比 │
│ UserService.query() │ 35.2% │
│ DBHelper.executeQuery() │ 28.5% │
│ JSONParser.parse() │ 12.3% │
└─────────────────────────────────────┘
内存分析
Bash
┌─────────────────────────────────────┐
│ 对象分配统计 │
├─────────────────────────────────────┤
│ 类 │ 分配次数 │
│ User │ 1,234,567│
│ HashMap$Entry │ 567,890 │
│ String │ 234,567 │
└─────────────────────────────────────┘
MAT(Memory Analyzer Tool)
功能特点
- 分析堆快照(hprof文件)
- 找出内存泄漏
- 大对象分析
- 对象引用链
使用方法
Bash
# 1. 生成堆快照
jmap -dump:format=b,file=heap.hprof <pid>
# 2. MAT打开分析
File → Open Heap Dump
核心功能
Leak Suspects Report:
Bash
┌─────────────────────────────────────┐
│ 内存泄漏嫌疑对象 │
├─────────────────────────────────────┤
│ Problem Suspect 1: │
│ The class UserCache loaded by... │
│ occupies 256MB (32%) of heap │
│ │
│ Problem Suspect 2: │
│ 1024 instances of User │
│ loaded by... │
└─────────────────────────────────────┘
Dominator Tree:
Bash
对象支配树,显示对象及其引用对象大小
UserCache (256MB)
├── users HashMap (200MB)
│ ├── User[1024] (150MB)
│ └── Entry[2048] (50MB)
└── index ArrayList (56MB)
对象引用链:
text
右键对象 → Path to GC Roots
显示对象为何无法被回收:
Thread main
→ locals (栈帧局部变量)
→ UserService
→ userCache
→ User[id=1001]
Arthas线上诊断
安装启动
text
# 下载
curl -O https://arthas.aliyun.com/arthas-boot.jar
# 启动(选择进程)
java -jar arthas-boot.jar
常用命令
text
# 综合面板
dashboard
# 线程分析
thread # 所有线程
thread -n 5 # CPU占用最高的5个线程
thread <id> # 指定线程详情
thread -b # 找阻塞线程
# 内存分析
memory # 内存概况
heapdump # 导出堆快照
# 方法监控
monitor -c 5 com.example.UserService.* # 每5秒统计调用次数
# 方法追踪(调用链)
stack com.example.UserService.query
# 方法耗时
trace com.example.UserService.query
# 查看方法参数和返回值
watch com.example.UserService.query "{params, returnObj}"
# 反编译查看源码
jad com.example.UserService
# 热更新代码
retransform /path/to/UserService.class
trace命令详解
text
trace com.example.Service.process '#cost > 100'
输出:
`---[120.45ms] com.example.Service:process()
+---[80.23ms] com.example.Dao:query()
| `---[75.12ms] DB:execute()
+---[35.12ms] com.example.Cache:get()
`---[5.10ms] com.example.Util:parse()
找出耗时最多的方法:Dao.query()
GC日志分析工具
GCViewer
text
# 分析GC日志
java -jar gcviewer.jar gc.log
GCEasy(在线分析)
text
上传GC日志文件到 https://gceasy.io
输出报告:
- GC次数统计
- GC时间分布
- 内存使用趋势
- 问题诊断建议
Flame Graph火焰图
text
# 生成CPU火焰图
# 1. 使用async-profiler采样
java -jar async-profiler.jar -d 60 -f flamegraph.html <pid>
# 2. 分析火焰图
# 横轴:方法调用占比
# 纵轴:调用栈深度
# 颜色:不同方法
# 高峰:热点方法
工具使用场景
| 场景 | 推荐工具 |
|---|---|
| 实时监控 | VisualVM, JConsole |
| 内存泄漏 | MAT, JProfiler |
| CPU热点 | JProfiler, async-profiler |
| 线上诊断 | Arthas |
| GC分析 | GCEasy, GCViewer |
| 链路追踪 | SkyWalking |
注意事项
分析工具可能影响性能,生产环境谨慎使用
MAT分析大堆快照需要足够内存
Arthas可以在线诊断,无需重启
定期导出堆快照存档,便于对比分析
结合多个工具综合分析,单一工具可能遗漏问题
要点总结
- VisualVM/JConsole适合实时监控
- MAT分析堆快照,定位内存泄漏
- JProfiler分析CPU热点和内存分配
- Arthas线上诊断,trace/watch监控方法
- GCEasy在线分析GC日志
📝 发现内容有误?点击此处直接编辑