1. 概述
在JVM性能调优和故障排查中,命令行工具是开发运维人员最锋利的"手术刀"。如图1所示,这些工具可以分为三类:
核心工具家族:
- 进程定位:jps
- 运行时监控:jstat
- 参数管理:jinfo
- 内存分析:jmap/jhat
- 线程分析:jstack
- 全能工具:jcmd
- 远程诊断:jstatd
2. jps:查看正在运行的Java进程
2.1 基础用法
$ jps
1234 Jps
5678 Main
9101 Worker
2.2 参数详解
典型应用场景:
- 快速定位应用PID
- 验证JVM参数是否生效
- 检查多个Java进程的启动配置
3. jstat:查看JVM统计信息
3.1 监控GC活动
$ jstat -gcutil 5678 1000 5
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 99.99 63.78 29.87 95.34 92.10 135 2.017 5 0.987 3.004
3.2 内存分区监控
关键指标解读:
- YGC/YGCT:年轻代GC次数/耗时
- FGC/FGCT:老年代GC次数/耗时
- GCT:总GC耗时
4. jinfo:实时查看和修改JVM配置参数
4.1 参数查看实战
$ jinfo 5678
Attaching to process ID 5678, please wait...
VM Arguments:
java.awt.headless=true
-Xms1024m
-Xmx2048m
-XX:MaxMetaspaceSize=256m
4.2 动态修改参数
典型修改案例:
- 调整日志级别:
<font style="background-color:rgb(252, 252, 252);">jinfo -flag +PrintGC 5678</font>
- 关闭JMX:
<font style="background-color:rgb(252, 252, 252);">jinfo -flag -Dcom.sun.management.jmxremote 5678</font>
注意:仅支持修改<font style="background-color:rgb(252, 252, 252);">manageable</font>
类型的参数(可通过<font style="background-color:rgb(252, 252, 252);">java -XX:+PrintFlagsFinal | grep manageable</font>
查询)
5. jmap:导出内存映像文件&内存使用情况
5.1 内存快照生成
# 生成堆转储文件
$ jmap -dump:format=b,file=heap.hprof 5678# 实时内存统计
$ jmap -histo:live 5678 | head -n 10num #instances #bytes class name
----------------------------------------------1: 23456 13421728 [B2: 12345 5678900 java.lang.String3: 6789 3456780 java.util.HashMap$Node
5.2 内存泄漏分析实战
关键诊断步骤:
- 使用
<font style="background-color:rgb(252, 252, 252);">-histo</font>
查看大对象分布 - 生成堆转储文件进行深度分析
- 对比多次dump文件观察对象增长
6. jhat:JDK自带堆分析工具
6.1 基础分析流程
$ jhat -port 7000 heap.hprof
Reading from heap.hprof...
Snapshot resolved.
Server is ready on http://localhost:7000/
6.2 分析界面解读
核心功能:
- 对象直方图查询
- 对象引用链追踪
- 根集可达性分析
注意:生产环境建议使用MAT或VisualVM替代,jhat适合快速分析
7. jstack:打印JVM中线程快照
7.1 线程状态解析
7.2 死锁检测示例
$ jstack 5678 | grep -A 10 deadlock
"Thread-1" #12 prio=5 os_prio=0 tid=0x00007f48740c4800 nid=0x5e03 waiting for monitor entry [0x00007f486b5fe000]java.lang.Thread.State: BLOCKED (on object monitor)at com.example.DeadlockDemo.methodB(DeadlockDemo.java:25)- waiting to lock <0x000000076ab00000> - locked <0x000000076ab00010> "Thread-0" #11 prio=5 os_prio=0 tid=0x00007f48740c3000 nid=0x5e02 waiting for monitor entry [0x00007f486b6ff000]java.lang.Thread.State: BLOCKED (on object monitor)at com.example.DeadlockDemo.methodA(DeadlockDemo.java:15)- waiting to lock <0x000000076ab00010> - locked <0x000000076ab00000>
线程分析技巧:
- 使用
<font style="background-color:rgb(252, 252, 252);">top -Hp PID</font>
找到高CPU线程 - 将线程ID转换为16进制:
<font style="background-color:rgb(252, 252, 252);">printf "%x\n" 12345</font>
- 在jstack输出中搜索nid对应的线程
8. jcmd:多功能命令行
8.1 全能工具剖析
8.2 常用命令实战
# 列出所有可用诊断命令
$ jcmd 5678 help# 获取JVM启动参数
$ jcmd 5678 VM.flags# 强制触发Full GC
$ jcmd 5678 GC.run# 生成堆转储文件(替代jmap)
$ jcmd 5678 GC.heap_dump filename=heap.hprof
功能对比表:
功能 | jcmd命令 | 传统工具 |
---|---|---|
线程快照 | Thread.print | jstack |
堆转储 | GC.heap_dump | jmap -dump |
类加载统计 | GC.class_histogram | jmap -histo |
JFR记录 | JFR.start/JFR.dump | 需单独配置 |
9. jstatd:远程主机信息收集
9.1 远程监控架构
9.2 安全配置步骤
- 创建安全策略文件
java">grant codebase "file:${java.home}/../lib/tools.jar" {permission java.security.AllPermission;
};
- 启动jstatd服务
$ jstatd -J-Djava.security.policy=jstatd.policy -p 1099
- 远程连接验证
$ jps 192.168.1.100:1099
生产环境建议:
- 使用VPN或SSH隧道进行加密传输
- 限制访问IP地址范围
- 定期轮换安全证书
10. 常见问题与解决方案
10.1 经典问题排查矩阵
现象 | 诊断工具 | 关键操作步骤 |
---|---|---|
Java进程突然消失 | jps + 系统日志 | 1. 检查OOM Killer日志 2. 分析hs_err_pid.log 3. 监控系统资源使用 |
内存持续增长 | jstat + jmap | 1. 观察GC频率变化 2. 生成堆转储对比 3. MAT分析对象引用链 |
线程池阻塞 | jstack + top | 1. 定位BLOCKED状态线程 2. 分析锁竞争关系 3. 检查线程等待条件 |
FullGC频繁 | jstat + jinfo | 1. 检查内存分配比例 2. 分析对象晋升策略 3. 调整SurvivorRatio参数 |
类加载失败 | jcmd + verbose日志 | 1. 查看ClassLoader统计 2. 检查元空间使用 3. 分析依赖冲突 |
10.2 内存溢出(OOM)实战
关键配置参数:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dumps
-XX:OnOutOfMemoryError="kill -9 %p" # 自动清理进程
11. 高频面试问题与解答
11.1 工具原理类
Q1:jstat和jmap的本质区别是什么?
- jstat通过JMX接口获取实时统计值,采样周期可配置
- jmap需要挂起线程生成完整堆快照,会产生STW停顿
Q2:线上环境如何安全使用jstack?
- 避免直接执行
<font style="background-color:rgb(252, 252, 252);">kill -3</font>
可能破坏标准输出 - 配合
<font style="background-color:rgb(252, 252, 252);">-F</font>
参数强制获取线程快照 - 多次采样对比(建议至少3次)
- 优先使用jcmd Thread.print命令
11.2 实战操作类
Q3:如何快速定位CPU飙高问题?
# 1. 定位高CPU进程
top -c# 2. 转换线程ID为16进制
printf "%x\n" 12345# 3. 抓取线程栈并分析
jcmd 5678 Thread.print | grep nid=0x3039 -A 15
Q4:Metaspace溢出有哪些排查手段?
<font style="background-color:rgb(252, 252, 252);">jstat -gcmetacapacity</font>
查看元空间使用<font style="background-color:rgb(252, 252, 252);">jcmd GC.class_stats</font>
统计类加载详情- 使用arthas的classloader命令分析
- 添加
<font style="background-color:rgb(252, 252, 252);">-XX:NativeMemoryTracking=detail</font>
参数
11.3 高级调优类
Q5:G1回收器应该关注哪些jstat指标?
Q6:如何诊断Direct Memory泄漏?
<font style="background-color:rgb(252, 252, 252);">jmap -histo:live</font>
查找ByteBuffer实例- 添加
<font style="background-color:rgb(252, 252, 252);">-XX:MaxDirectMemorySize</font>
限制大小 - 使用NMT监控本地内存:
jcmd 5678 VM.native_memory detail.diff
全工具速查手册:
最佳实践建议:
- 生产环境必备诊断命令:
alias jvmdiag="jcmd PID VM.flags; jstat -gcutil PID 1000 3; jstack PID"
- 建立标准化检查清单:
- 内存使用趋势图
- GC频率/耗时记录
- 线程状态分布统计
- 类加载/卸载数量监控
通过系统掌握这些命令行工具,开发者可以快速构建起立体化的JVM诊断能力,无论是应对突发的线上故障,还是进行深度的性能调优,都能做到有的放矢、游刃有余。建议在日常开发中定期执行健康检查,形成"预防为主,快速定位"的运维体系。