jcmd
是 Oracle JDK(Java Development Kit)自 JDK 7 起引入的一个强大的诊断工具,用于与正在运行的 JVM(Java Virtual Machine)实例进行交互。它允许用户执行各种诊断命令,比如线程堆栈分析、堆转储、GC 信息、类加载器统计等,非常适合在生产环境中对 Java 应用程序进行调试和监控。
jcmd
命令基本语法jcmd <pid | main-class> <command> [options]
:目标 Java 进程的进程 ID。
:目标 Java 应用的主类名(可以省略 jar 路径)。
:具体的诊断命令,比如 VM.flags
。[options]
:命令附带的参数(具体取决于命令)。jcmd
970 com.dzy.Main
67890 org.apache.catalina.startup.Bootstrap
表示当前有两个 Java 进程在运行,它们的进程 ID 分别是 970 和 67890。
jcmd <pid> help
jcmd 970 help
列出该 JVM 实例支持的所有命令:
970:
VM.version
VM.command_line
VM.flags
Thread.print
GC.heap_info
GC.run
GC.class_histogram
...
jcmd <pid> VM.version
jcmd 970 VM.version
970:
Java HotSpot(TM) 64-Bit Server VM version 17.0.9+11-LTS-201
JDK 17.0.9
jcmd <pid> VM.command_line
jcmd 970 VM.command_line
Command line: -Xmx2G -Xms1G -Dspring.profiles.active=prod -jar app.jar
jcmd <pid> VM.flags
jcmd 970 VM.flags
-XX:InitialHeapSize=1073741824 -XX:MaxHeapSize=2147483648 -XX:+UseG1GC
jstack
)jcmd <pid> Thread.print
jcmd 970 Thread.print
列出所有线程的栈信息,包括锁等待、阻塞等,非常适合死锁分析。
jcmd <pid> GC.run
jcmd 970 GC.run
此命令不会显示太多输出,但会触发一次完全 GC。
jcmd <pid> GC.heap_info
jcmd 970 GC.heap_info
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
...
Heap Usage:
G1 Heap:
regions = 2048
capacity = 2048M
used = 1024M
free = 1024M
jcmd <pid> GC.heap_dump /path/to/heapdump.hprof
jcmd 970 GC.heap_dump /tmp/app-heap.hprof
文件可以用 MAT 或 VisualVM 分析。
jcmd <pid> GC.class_histogram
jcmd 970 GC.class_histogram
或者输出到文件
jcmd 970 GC.class_histogram > histogram.txt
num #instances #bytes class name
----------------------------------------------
1: 10000 1600000 [C
2: 5000 800000 java.lang.String
3: 3000 720000 java.util.HashMap
jcmd <pid> VM.class_loader_stats
jcmd 970 VM.class_loader_stats
统计各类加载器加载的类数量、占用内存等信息。
jcmd <pid> Thread.print
jcmd 970 Thread.print
系统会显示哪些线程在等待锁、拥有锁,如果存在死锁,会提示 Found one Java-level deadlock
.
jcmd <pid> VM.native_memory summary
jcmd 970 VM.native_memory summary
需要启动 JVM 时开启:
-XX:NativeMemoryTracking=summary
jcmd <pid> VM.system_properties
jcmd 970 VM.system_properties
JFR.start
, JFR.dump
, JFR.stop
# 启动 JFR
jcmd 970 JFR.start name=profile settings=profile duration=60s filename=/tmp/recording.jfr
# 手动 dump
jcmd 970 JFR.dump name=profile filename=/tmp/manual.jfr
# 停止 JFR
jcmd 970 JFR.stop name=profile
jcmd <pid> Compiler.codecache
jcmd 970 Compiler.codecache
jcmd $(pidof java) GC.heap_info
jcmd $(pidof java) GC.heap_dump /tmp/dump-$(date +%s).hprof
jcmd $(pidof java) Thread.print > /tmp/thread-dump.log
watch -n 60 "jcmd $(pidof java) GC.run"
jcmd <pid> GC.heap_info
jcmd <pid> GC.class_histogram
jcmd <pid> GC.run
jcmd <pid> GC.class_histogram
比较前后对象数量是否减少,分析垃圾回收效率。
top -Hp <pid>
print "%x/n" <pid>
jcmd
输出中查找栈jcmd <pid> Thread.print | grep -A 20 0x3039
jcmd <pid> GC.class_histogram > before.txt
# 10分钟后
jcmd <pid> GC.class_histogram > after.txt
diff before.txt after.txt
jcmd <pid> VM.flags
jcmd <pid> VM.command_line
jcmd
只能对当前用户启动的 Java 进程使用,或者以 root
权限运行。jstack
、jmap
等相比,jcmd
更统一、更高效。功能 | 命令 |
---|---|
查看进程列表 | jcmd |
查看支持命令 | jcmd |
JVM 版本 | jcmd |
JVM 启动参数 | jcmd / VM.flags |
手动 GC | jcmd |
打印线程堆栈 | jcmd |
类占用分析 | jcmd |
原生内存 | jcmd |
启动/导出 JFR | jcmd |