jcmd诊断内存隐患的关键是不触发stw、不增开销、不改配置;需先用jcmd -l查pid并确认nmt已启用(-xx:nativememorytracking=summary),再通过vm.native_memory summary毫秒级识别[thread]/[class]/[internal]异常增长,辅以thread.print和gc.class_histogram交叉验证,禁用gc.run与gc.heap_dump保障生产安全。

用 jcmd 诊断内存隐患,关键在于“不触发 STW、不增开销、不改配置”。它本身是 JVM 内置通道,命令执行快、资源消耗低,只要提前开启 NMT(Native Memory Tracking),就能在不中断业务的前提下定位堆外内存异常、线程失控、元数据膨胀等典型隐患。
第一步:确认进程并检查 NMT 是否就绪
先用 jcmd -l 列出所有 Java 进程,找到目标 PID:
- 输出第二列是 PID,第三列是主类或 jar 路径;若第三列为空,可查
/proc/<pid>/cmdline</pid>确认启动方式 - 执行 jcmd
VM.native_memory summary ,如果返回 “Native memory tracking is not enabled”,说明未启用 NMT,需重启加-XX:NativeMemoryTracking=summary - 已启用时,summary 命令毫秒级返回,不会卡住进程,适合高频巡检
第二步:聚焦三类高危内存信号
重点关注 native 内存中增长异常的模块,它们往往比堆泄漏更隐蔽:
- [thread] 持续上升 → 线程数失控(如虚拟线程未正确 close、线程池未设界、定时任务重复注册)
- [internal] 显著偏高或持续增长 → 虚拟线程元数据泄漏、JIT 编译缓存膨胀、DirectByteBuffer Cleaner 积压
- [class] 异常高(尤其搭配动态代理/Groovy/OSGi)→ 类加载器泄漏,常见于热部署或插件化场景
第三步:配合轻量命令交叉验证
单看 NMT 不够,需用其他 jcmd 子命令快速佐证:
-
jcmd
VM.native_memory detail (慎用):仅在低峰期执行,查看 malloc 调用栈,确认是否大量来自Unsafe_AllocateMemory或DirectByteBuffer -
jcmd
Thread.print :比 jstack 更稳定,能捕获 IN_NATIVE 卡死线程;搜java.lang.VirtualThread和carrier=null可发现挂起的虚拟线程 -
jcmd
GC.class_histogram :不 dump 堆,秒出类实例数量 TOP 20,快速识别是否某类对象暴增(如 ByteBuf、FutureTask)
第四步:生产环境安全操作建议
避免踩坑,守住“零侵入”底线:
- 禁用
jcmd <pid> GC.run</pid>和GC.heap_dump—— 它们可能引发 Full GC 或长时间暂停,不符合“不影响生产”前提 - NMT detail 模式性能开销达 5–10%,只在问题复现时临时启用,排查后无需重启即可用
VM.native_memory shutdown关闭 - 容器环境务必确认挂载了
/proc,且 JDK 版本 ≥ 8u212 并启用-XX:+UseContainerSupport,否则 jcmd 可能返回空或权限错误
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











