一、命令行工具
1. 工具概览
| 工具 | 核心功能 | 使用场景 | 关键字 |
|---|---|---|---|
| jps | 查看Java进程列表 | 快速定位目标进程 | 进程ID、主类名 |
| jstack | 生成线程栈快照 | 死锁分析、线程阻塞、CPU高占用 | 线程状态、锁持有、死锁检测 |
| jmap | 生成堆转储、查看内存使用 | 内存泄漏、大对象分析、堆内存结构 | 堆转储、对象统计、类加载 |
| jstat | 监控JVM统计信息 | GC频率、内存使用、类加载情况 | GC时间、内存使用率、类加载数 |
| jinfo | 查看/修改JVM配置 | 动态调整JVM参数、查看运行时配置 | 系统属性、JVM参数、动态修改 |
2. 核心工具详解
jps(Java Process Status)
-
功能:列出当前运行的Java进程,显示进程ID和主类名
-
常用命令 :
bashjps -l # 显示完整主类名 jps -v # 显示JVM启动参数 jps -m # 显示主类的传入参数 -
使用场景:快速定位目标Java进程,获取进程ID
jstack(Java Stack Trace)
-
功能:生成线程栈快照,用于分析线程状态、死锁、阻塞等问题
-
常用命令 :
bashjstack <pid> # 生成线程栈快照 jstack -l <pid> # 显示锁信息(死锁分析必备) jstack -F <pid> # 强制生成快照(进程无响应时) -
面试题:如何使用jstack分析死锁?
回答步骤 :-
使用
jps获取目标进程ID -
执行
jstack -l <pid> > jstack.log生成线程栈快照 -
搜索日志中的
Found one Java-level deadlock关键字 -
分析死锁线程的锁持有情况,定位死锁原因
示例输出:Found one Java-level deadlock:
"Thread-1":
waiting for ownable synchronizer 0x000000076b600580, (a java.util.concurrent.locks.ReentrantLockNonfairSync), which is held by "Thread-0" "Thread-0": waiting for ownable synchronizer 0x000000076b6005b8, (a java.util.concurrent.locks.ReentrantLockNonfairSync),
which is held by "Thread-1"
-
jmap(Java Memory Map)
-
功能:生成堆转储文件、查看堆内存使用情况
-
常用命令 :
bashjmap -dump:format=b,file=heap.hprof <pid> # 生成堆转储 jmap -histo <pid> # 显示对象统计信息(类名、实例数、内存占用) jmap -histo:live <pid> # 显示存活对象统计信息 jmap -heap <pid> # 显示堆内存结构 -
使用场景:内存泄漏分析、大对象定位、堆内存结构查看
jstat(Java Statistics Monitoring)
-
功能:监控JVM运行时统计信息,包括GC、内存、类加载等
-
常用命令 :
bashjstat -gc <pid> <interval> <count> # 监控GC情况,每interval毫秒输出一次,共count次 jstat -gcutil <pid> # 显示GC利用率(百分比) jstat -class <pid> # 显示类加载情况 jstat -compiler <pid> # 显示JIT编译情况 -
输出示例 :
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 0.0 1024.0 0.0 0.0 8192.0 1024.0 20480.0 5120.0 5120.0 1024.0 512.0 128.0 5 0.020 1 0.050 0.070
jinfo(Java Configuration Info)
-
功能:查看和修改JVM配置参数
-
常用命令 :
bashjinfo <pid> # 显示JVM参数和系统属性 jinfo -flags <pid> # 显示JVM启动参数 jinfo -sysprops <pid> # 显示系统属性 jinfo -flag <name> <pid> # 查看单个JVM参数值 jinfo -flag +<name> <pid> # 开启JVM参数(布尔类型) jinfo -flag -<name> <pid> # 关闭JVM参数(布尔类型) -
使用场景:动态调整JVM参数、查看运行时配置
二、可视化工具
1. 工具对比
| 工具 | 功能全面性 | 使用难度 | 线上可用性 | 核心优势 |
|---|---|---|---|---|
| JConsole | 基础 | 低 | 可远程连接 | 内置JDK,轻量级 |
| VisualVM | 全面 | 中 | 可远程连接 | 功能丰富,插件扩展 |
| Arthas | 强大 | 中 | 高(无需重启) | 线上诊断利器,动态注入 |
2. 核心工具详解
JConsole
- 启动方式 :
jconsole或 JDK/bin/jconsole.exe - 核心功能 :
- 内存监控:堆内存、非堆内存使用情况
- 线程监控:线程状态、死锁检测
- GC监控:GC频率、时间
- 类加载监控:类加载数、卸载数
- 使用场景:基础监控,适合开发测试环境
VisualVM
- 启动方式 :
jvisualvm或 JDK/bin/jvisualvm.exe - 核心功能 :
- 内存分析:堆转储分析、大对象定位
- 线程分析:线程栈快照、死锁检测
- GC分析:GC日志分析、内存泄漏检测
- 抽样器:CPU抽样、内存抽样
- 插件扩展:支持多种插件,如MAT集成、JProfiler集成
- 使用场景:功能全面的监控和分析工具,适合开发测试和生产环境
Arthas
-
核心功能:线上诊断利器,无需重启应用
-
启动方式:
bashcurl -O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar <pid> -
常用命令:
dashboard:实时监控面板(CPU、内存、线程)thread:线程状态分析,死锁检测heapdump:生成堆转储jad:反编译类watch:方法执行监控trace:方法调用链路追踪redefine:热更新代码
-
面试题:如何使用Arthas排查线上问题?
回答模板 :Arthas是线上诊断利器,可通过以下步骤排查问题:
-
连接目标进程:
bashjava -jar arthas-boot.jar <pid> -
实时监控状态:
bashdashboard # 查看CPU、内存、线程实时状态 -
分析CPU高占用:
bashthread -n 3 # 查看CPU占用前3的线程 thread <tid> # 查看具体线程栈 -
分析内存问题:
bashheapdump /tmp/heap.hprof # 生成堆转储 jad <className> # 反编译类,查看代码 -
监控方法执行:
bashwatch <className> <methodName> "{params, returnObj}" -x 2 # 监控方法参数和返回值 trace <className> <methodName> # 追踪方法调用链路 -
热更新代码:
bashredefine <classFile> # 热更新类文件 -
死锁检测:
bashthread -b # 查看阻塞线程 thread -d # 检测死锁
Arthas的核心优势是无需重启应用,适合线上环境诊断,可快速定位和解决问题。
-
三、堆转储分析工具
1. 工具对比
| 工具 | 类型 | 核心功能 | 优势 | 适用场景 |
|---|---|---|---|---|
| MAT(Memory Analyzer Tool) | 开源 | 内存泄漏分析、大对象定位 | 免费、内存泄漏检测强大 | 内存泄漏分析、大对象定位 |
| JProfiler | 商业 | 全面的性能分析 | 功能强大、易用性高、实时监控 | 内存分析、CPU分析、线程分析 |
2. MAT(Memory Analyzer Tool)
- 核心功能 :
- 内存泄漏检测:通过支配树、直方图等分析内存泄漏
- 大对象定位:快速找到占用内存最多的对象
- 引用关系分析:查看对象间的引用链
- 线程分析:查看线程栈和锁信息
- 使用步骤 :
- 使用
jmap -dump:format=b,file=heap.hprof <pid>生成堆转储 - 启动MAT,打开堆转储文件
- 运行"Leak Suspects Report"分析内存泄漏
- 查看"Histogram"分析对象统计信息
- 查看"Dominator Tree"分析对象支配关系
- 使用
- 核心报告 :
- Leak Suspects:内存泄漏嫌疑报告
- Histogram:对象数量和大小统计
- Dominator Tree:对象支配树,显示对象的内存支配关系
- Path to GC Roots:对象到GC Roots的引用链
3. JProfiler
- 核心功能 :
- 内存分析:堆内存使用情况、对象引用关系
- CPU分析:方法调用次数、耗时统计
- 线程分析:线程状态、死锁检测
- 热点方法分析:找出耗时最多的方法
- 实时监控:实时监控JVM运行状态
- 使用场景:商业项目的性能分析,功能全面,易用性高
四、工具使用最佳实践
1. 日常监控
- 使用jstat定期监控GC情况,及时发现内存问题
- 使用JConsole 或VisualVM进行实时监控
- 线上环境建议开启GC日志,便于后续分析
2. 故障排查流程
-
定位问题:
- CPU高:使用
top+jstack分析线程栈 - 内存泄漏:使用
jmap生成堆转储,MAT分析 - 线程阻塞:使用
jstack分析线程状态 - 死锁:使用
jstack -l或Arthas thread -d检测
- CPU高:使用
-
分析问题:
- 查看线程栈中的锁持有情况
- 分析堆转储中的大对象和引用关系
- 结合GC日志分析GC频率和时间
-
解决问题:
- 代码优化:修复死锁、减少对象创建
- JVM参数调整:调整堆大小、GC收集器
- 资源优化:释放无用资源、优化缓存策略
3. 线上环境注意事项
- 使用Arthas进行线上诊断,避免影响应用性能
- 生成堆转储时注意:
- 堆转储文件较大,建议输出到磁盘空间充足的目录
- 生成堆转储会暂停应用(约几秒到几十秒),建议在低峰期执行
- 可使用
jmap -dump:live只生成存活对象,减少文件大小
五、面试题汇总
1. 如何使用jstack分析死锁?
回答:
- 使用
jps获取目标进程ID - 执行
jstack -l <pid> > jstack.log生成线程栈快照 - 搜索日志中的
Found one Java-level deadlock关键字 - 分析死锁线程的锁持有情况:
- 查看线程状态(BLOCKED)
- 查看"waiting for ownable synchronizer"(等待的锁)
- 查看"locked"(已持有的锁)
- 定位死锁原因:两个或多个线程相互持有对方需要的锁
2. 如何使用Arthas排查线上问题?
回答:
- 连接目标进程:
java -jar arthas-boot.jar <pid> - 使用
dashboard查看实时状态,定位异常指标(CPU、内存、线程) - 根据异常指标选择对应命令:
- CPU高:
thread -n 3查看CPU占用前3的线程 - 内存问题:
heapdump生成堆转储,结合MAT分析 - 方法执行异常:
watch监控方法参数和返回值,trace追踪调用链路 - 死锁:
thread -d检测死锁
- CPU高:
- 如需代码修复,使用
jad反编译类,redefine热更新代码 - 问题解决后,使用
quit退出Arthas
3. 如何分析内存泄漏?
回答:
- 使用
jstat -gc <pid>监控GC情况,观察老年代内存是否持续增长 - 使用
jmap -histo:live <pid>查看存活对象统计,定位大对象 - 使用
jmap -dump:format=b,file=heap.hprof <pid>生成堆转储 - 使用MAT分析堆转储:
- 运行"Leak Suspects Report"查找内存泄漏嫌疑
- 查看"Dominator Tree"分析对象支配关系
- 查看"Path to GC Roots"分析对象引用链
- 定位内存泄漏源:找出长期存活的对象和导致其无法回收的引用链
总结
JVM性能监控与故障排查工具是Java开发者必备技能,不同工具适用于不同场景:
- 命令行工具:轻量级、适合快速定位问题
- 可视化工具:功能全面、适合深入分析
- Arthas:线上诊断利器、无需重启应用
- 堆转储分析工具:内存泄漏分析的核心工具
掌握这些工具的使用方法,结合具体业务场景进行调优,能够有效提升应用性能和稳定性。