Zzzxb's Blog

你要静心学习那份等待时机的成熟的情绪,也要你一定保有这份等待之外的努力和坚持。

JDK 工具使用 May 09, 2026

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
  1. 别只看”BLOCKED”,要看”谁持有锁” 注意:锁地址 <0x…> 是对应的,找到谁 locked 同一把锁
  2. 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 -dumpjmap -histo:live 这类会暂停应用的命令,千万小心。