jcmd:一个命令代替一堆 j 工具
更新时间:2026-09-20。从 JDK 8 起,官方把线程、堆、JVM 信息等诊断能力收敛到
jcmd,新版本里 jstack/jmap 的部分能力甚至被标记废弃。先用 jps 拿 PID。线程栈细节见 jstack,堆分析见 jmap。
一、先看这个进程支持哪些命令
bash
jcmd 20480 help # 列出该 JVM 支持的全部诊断命令
jcmd 20480 help Thread.print # 看某个子命令的参数说明
jcmd # 不带参数 = 列出本机 JVM(类似 jps)二、最高频的 6 个子命令
| 子命令 | 等价旧命令 | 用途 |
|---|---|---|
Thread.print | jstack -l | 打印线程栈,定位 CPU 高/卡死/死锁 |
GC.heap_dump <file> | jmap -dump:format=b | 导出堆转储供 MAT 分析 |
GC.class_histogram | jmap -histo | 对象直方图,快速看谁占内存 |
VM.flags | jinfo -flags | 看 JVM 实际生效的所有 flag |
VM.system_properties | jinfo -sysprops | 看 -D 系统属性 |
VM.native_memory | — | 看堆外内存(需先开 NMT) |
bash
jcmd 20480 Thread.print > /tmp/t.txt
jcmd 20480 GC.heap_dump /tmp/heap.hprof
jcmd 20480 GC.class_histogram | head -30
jcmd 20480 VM.flags | tr ' ' '\n' | grep -i heapsize三、几组实用场景
看「我设的 -Xmx 到底生效没有」:容器里最容易出现配置没生效,用 jcmd <pid> VM.flags 看 MaxHeapSize 的真实值,配合 JVM 容器内存限制。
堆外/直接内存排查:启动加 -XX:NativeMemoryTracking=summary,然后:
bash
jcmd 20480 VM.native_memory summary scale=MB # 看 Java Heap / Thread / Class / Internal
jcmd 20480 VM.native_memory baseline # 打基线
jcmd 20480 VM.native_memory detail.diff # 一段时间后对比增量,定位 native 泄漏GC 与类加载:jcmd <pid> GC.class_stats(需 -XX:+UnlockDiagnosticVMOptions)看每个类占用;jcmd <pid> VM.metaspace 看元空间。
四、注意与坑
GC.heap_dump默认导 full(含不可达对象),文件和堆一样大,保证磁盘空间;想先 Full GC 再导可用GC.heap_dump -all=false(只存活对象)。生产建议低峰或对镜像执行。jcmd <pid> GC.run会主动触发一次 Full GC,不要在生产乱用;排查显式System.gc()问题时才需要关注。- 子命令大小写敏感;旧 JDK 支持的命令比新 JDK 少,以
help实际列出为准。 - 容器里要在目标容器的命名空间执行(
kubectl exec/docker exec进去),宿主机直接 attach 通常失败。 - attach 依赖
/tmp下的 attach 机制与同用户权限,只读文件系统或不同用户会连不上。
总结
jcmd 是 JDK8+ 统一诊断入口:先 jcmd <pid> help 看支持项,线程栈用 Thread.print、导堆用 GC.heap_dump、快速看内存用 GC.class_histogram、确认实际配置用 VM.flags、查堆外靠开启 NMT 后的 VM.native_memory 基线对比;它逐步替代 jstack/jmap/jinfo,且子命令大小写敏感、以目标版本 help 为准;生产上导堆要留足磁盘并避开高峰、不要随便 GC.run,容器内必须进目标命名空间且用同用户 attach。