JDK 工具使用 May 09, 2026
- 1. javac - 编译
- 2. java - 运行
- 3. jar - 打包
- 4. jps - 查看 Java 进程
- 5. jstack - 查看线程堆栈(排查死锁、CPU 飙高)
- 6. jmap - 内存分析(排查 OOM)
- 7. jstat - 监控 GC(看内存趋势)
- 8. jinfo - 查看/修改 JVM 参数
- 9. jcmd - 新一代全能工具
- 10. javap - 反编译 class
- 11. keytool - 管理证书
- 12. jarsigner - 签名 jar
- 场景1:线上 CPU 100%,如何快速定位?
- 场景2:内存溢出,找谁占的
- 场景3:应用假死,查是否死锁
- 场景4:检查 JVM 启动参数
- 场景5:模拟内存溢出(学习用)
- 六、常用组合口诀
- 七、提前预防(生产环境加参数,免得出问题抓瞎)
- 八、快速问题速查表
1. javac - 编译
# 基本用法
javac Hello.java
# 指定输出目录
javac -d ./classes Hello.java
# 编译多个文件(带依赖)
javac -cp ./lib/* -d ./classes src/*.java
# 指定源码版本(避免默认版本问题)
javac -source 1.8 -target 1.8 Hello.java
2. java - 运行
# 运行单个类
java Hello
# 指定 classpath 运行
java -cp ./classes:./lib/mysql.jar com.example.Main
# 运行 jar 包(需要 MANIFEST.MF 定义了 Main-Class)
java -jar myapp.jar
# 设置内存大小运行
java -Xms512m -Xmx2g -jar myapp.jar
# 打印 GC 详细信息
java -XX:+PrintGCDetails -jar myapp.jar
3. jar - 打包
# 创建 jar 包
jar cf myapp.jar *.class
# 创建可执行 jar(指定入口点)
jar cfe myapp.jar com.example.Main -C classes/ .
# 查看 jar 包内容
jar tf myapp.jar
# 解压 jar 包
jar xf myapp.jar
# 更新 jar 包中的文件
jar uf myapp.jar newfile.class
4. jps - 查看 Java 进程
# 列出所有 Java 进程(显示进程 ID + 主类名)
jps
# 输出示例:
# 12345 MainApp
# 67890 Jps (这个就是 jps 自己)
# 显示完整包名
jps -l
# 12345 com.example.MainApp
# 显示传给 main 方法的参数
jps -v
# 12345 MainApp -Xms512m -Xmx2g
# 组合使用最实用
jps -lv
5. jstack - 查看线程堆栈(排查死锁、CPU 飙高)
# 基本用法(打印所有线程)
jstack 12345
# 输出到文件分析
jstack 12345 > thread_dump.txt
# 只打印锁相关信息(排查死锁)
jstack -l 12345
# 如果进程卡死加 -F 强制
jstack -F 12345
# 实战:找到 CPU 最高的线程
# 1. top -H -p 12345 # 找到 CPU 最高的线程 ID(比如 23456)
# 2. printf "%x\n" 23456 # 转十六进制 5ba0
# 3. jstack 12345 | grep -A 20 5ba0
- 别只看”BLOCKED”,要看”谁持有锁” 注意:锁地址 <0x…> 是对应的,找到谁 locked 同一把锁
- RUNNABLE 不一定有问题,WAITING 不一定没问题 ❌ 误判:看到大量 WAITING 就认为线程在休息 实际上可能是线程池满了,都在等队列 ✅ 需要配合看: 1. 线程堆栈里的业务代码 2. 系统整体负载(CPU、内存) 3. 响应时间等业务指标
6. jmap - 内存分析(排查 OOM)
# 查看堆内存使用情况
jmap -heap 12345
# 查看存活对象统计(触发 FGC)
jmap -histo:live 12345 > objects.txt
# 导出整个堆 dump(重要!)
jmap -dump:live,format=b,file=heap.hprof 12345
# 只看某个类的情况
jmap -histo 12345 | grep MyClass
# ⚠️ 严重警告:jmap -dump 会暂停应用(STW)
jmap -dump:live,format=b,file=heap.hprof 12345
# 如果堆很大(比如 32GB),可能暂停 30 秒以上
# ✅ 生产环境推荐:使用 jcmd(更安全)
jcmd 12345 GC.heap_dump /tmp/heap.hprof
# ✅ 或者用 gcore + jmap(先 core dump,后离线分析)
gcore 12345 # 生成 core.12345
jmap -dump:format=b,file=heap.hprof /usr/bin/java core.12345
# ⚠️ 这个会触发 Full GC,暂停所有线程
jmap -histo:live 12345
# ✅ 先看普通 histo(不触发 GC,但数字不太准)
jmap -histo 12345 | head -20
生产环境小技巧:提前配置 OOM 自动 Dump
最好别等出问题了才去执行
jmap(有时候进程已经撑不住或jmap会卡住),强烈建议在 Java 应用的启动参数中加上以下配置,这样在发生内存溢出(OOM)时,JVM 会自动把“犯罪现场”的 Dump 文件保存下来-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/your/dumps
7. jstat - 监控 GC(看内存趋势)
# 查看 GC 统计(每 1 秒打印一次,共 10 次)
jstat -gc 12345 1s 10
# 输出示例解读:
# S0C S1C S0U S1U EC EU OC OU MC MU
# 5120.0 5120.0 0.0 5120.0 32768.0 16384.0 131072.0 65536.0 44800.0 42000.0
# 精简版(只看 Full GC 次数)
jstat -gcutil 12345 1s 5
# S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
# 0.00 100.00 45.23 56.78 92.34 89.12 15 0.234 3 0.123 0.357
# 查看类加载情况
jstat -class 12345
# ❌ 间隔 10ms 太频繁,可能影响性能
jstat -gc 12345 10ms
# ✅ 正常情况 1 秒,紧急情况 100ms 也够
jstat -gc 12345 1s
8. jinfo - 查看/修改 JVM 参数
# 查看所有参数
jinfo 12345
# 查看某个参数
jinfo -flag PrintGCDetails 12345
# 输出:-XX:+PrintGCDetails (表示已开启)
# 动态修改参数(部分参数支持)
jinfo -flag +PrintGCDetails 12345
jinfo -flag -PrintGCDetails 12345
# 查看系统属性
jinfo -sysprops 12345 | grep user.dir
9. jcmd - 新一代全能工具
# 列出所有可执行命令
jcmd 12345 help
# 强制 GC
jcmd 12345 GC.run
# 堆信息(替代jstat -gc, 信息更容易懂)
jcmd 1234
5 GC.heap_info
# 导出 heap dump(比 jmap 更安全,暂停时间更短)
jcmd 12345 GC.heap_dump /tmp/heap.hprof
# 查看 VM 信息(替代jstat, 查看所有参数)
jcmd 12345 VM.info
# 查看系统属性
jcmd 12345 VM.system_properties
# 打印线程堆栈(替代 jstack,输出更结构化)
jcmd 12345 Thread.print
# 查看类加载统计
jcmd 12345 GC.class_stats
# 一键生成诊断报告(很实用!)
jcmd 12345 GC.class_histogram > /tmp/classes.txt
jcmd 12345 Thread.print > /tmp/threads.txt
jcmd 12345 GC.heap_dump /tmp/heap.hprof
jcmd 12345 VM.flags > /tmp/flags.txt
10. javap - 反编译 class
# 查看类的方法和字段(不显示字节码)
javap MyClass
# 查看完整字节码(最有用的参数)
javap -c MyClass
# 查看常量池、异常表、行号等详细信息
javap -v MyClass
# 实战:查看 String 拼接优化
javap -c Test.class | grep -A 5 "StringBuilder"
11. keytool - 管理证书
# 生成密钥对(包含公钥私钥)
keytool -genkeypair -alias mykey -keyalg RSA -keysize 2048 -keystore mykeystore.jks
# 导出公钥证书
keytool -exportcert -alias mykey -keystore mykeystore.jks -file mycert.crt
# 导入信任证书
keytool -importcert -alias trustedcert -keystore mytruststore.jks -file theircert.crt
# 查看 keystore 内容
keytool -list -v -keystore mykeystore.jks
# 删除条目
keytool -delete -alias mykey -keystore mykeystore.jks
# 修改密码
keytool -storepasswd -keystore mykeystore.jks
12. jarsigner - 签名 jar
# 对 jar 包签名
jarsigner -keystore mykeystore.jks myapp.jar mykey
# 验证签名
jarsigner -verify myapp.jar
# 验证并显示详细信息
jarsigner -verify -verbose -certs myapp.jar
场景1:线上 CPU 100%,如何快速定位?
# 第1步:找进程
ps aux | grep java
# 或
jps -l
# 第2步:找线程(PID=12345)
top -H -p 12345
# 记下 CPU 最高的线程 ID(比如 23456)
# 第3步:转十六进制
printf "%x\n" 23456
# 输出:5ba0
# 第4步:抓堆栈
jstack 12345 | grep -A 30 "5ba0"
# 看到具体哪行代码在消耗 CPU
场景2:内存溢出,找谁占的
# 第1步:查看对象统计
jmap -histo:live 12345 | head -20
# 看到占用最多的类
# 第2步:导出完整 dump
jmap -dump:live,format=b,file=heap.hprof 12345
# 第3步:分析(推荐用 MAT 或 jvisualvm)
# 或者直接用 jhat(不推荐,太慢)
jhat -port 7000 heap.hprof
# 浏览器打开 http://localhost:7000
场景3:应用假死,查是否死锁
# 方法1:jstack 直接提示
jstack -l 12345
# 输出尾部会显示 "Found one Java-level deadlock"
# 方法2:jcmd 同样效果
jcmd 12345 Thread.print
# 方法3:GUI 工具
jconsole 12345
# 点 "线程" → "检测死锁"
场景4:检查 JVM 启动参数
# 查看所有标志
jinfo -flags 12345
# 查看具体某个
jinfo -flag MaxHeapSize 12345
# 或通过 jcmd
jcmd 12345 VM.flags
# 查看系统属性(比如 user.home, java.class.path)
jcmd 12345 VM.system_properties
场景5:模拟内存溢出(学习用)
# 写测试类
cat > OOMTest.java << 'EOF'
import java.util.ArrayList;
import java.util.List;
public class OOMTest {
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
while (true) {
list.add(new byte[1024 * 1024]); // 每次加 1MB
}
}
}
EOF
# 编译并启动小内存限制
javac OOMTest.java
java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError OOMTest
# 很快就会 OOM,并自动生成 java_pid12345.hprof 文件
六、常用组合口诀
| 想做什么 | 命令组合 |
|---|---|
| 快速看一眼 JVM | jps -lv |
| 看 GC 是否频繁 | jstat -gcutil PID 1s |
| 定位 CPU 高 | top -H -p PID + jstack PID |
| 查死锁 | jstack -l PID |
| 找内存大户 | jmap -histo:live PID | head |
| 导出堆快照 | jmap -dump:live,format=b,file=heap.hprof PID |
| 查看运行参数 | jinfo -flags PID |
七、提前预防(生产环境加参数,免得出问题抓瞎)
# 推荐的生产环境 JVM 参数:
-XX:+HeapDumpOnOutOfMemoryError # OOM 自动 dump
-XX:HeapDumpPath=/opt/logs/heapdump # 指定路径
-XX:+PrintGCDetails # 打印 GC 详情
-XX:+PrintGCDateStamps # 带时间戳
-Xloggc:/opt/logs/gc.log # GC 日志输出
-XX:+UseGCLogFileRotation # GC 日志轮转
-XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=10M
八、快速问题速查表
| 现象 | 可能的命令 | 看什么 |
|---|---|---|
| CPU 高 | top -H + jstack |
RUNNABLE 且长时间不释放 CPU |
| 内存高 | jmap -histo:live |
业务类对象数量异常增长 |
| GC 频繁 | jstat -gcutil |
YGC/FGC 频率、耗时 |
| 应用卡死 | jstack -l |
BLOCKED 数量多,或死锁提示 |
| 类冲突 | -verbose:class |
某个类从哪个 jar 加载 |
| 参数未知 | jinfo -flags |
看是否有 -XX:+UseG1GC 等 |
| OOM 分析 | jcmd GC.heap_dump + MAT |
Leak Suspects 报告 |
线上生产环境操作时,先看文档确认命令影响,最好在测试环境验证过。尤其是 jmap -dump 和 jmap -histo:live 这类会暂停应用的命令,千万小心。