先执行jcmd VM.native_memory baseline建立基线,再在稳态下运行jcmd VM.native_memory summary.diff scale=MB比对各区域增量,重点关注Thread、Class、Internal、Other的reserved/committed变化,需避开GC/JIT噪声期以确保结果反映稳态偏移。

怎么用 jcmd 做 baseline 对比
NMT 本身不支持运行时开启,必须在 JVM 启动时加 -XX:NativeMemoryTracking=detail(或 summary)。调优前后对比的关键是「baseline」机制:它不是靠两次独立 dump 相减,而是记录一个内存快照作为基准,后续所有 diff 都相对于它计算。
实操步骤如下:
- 调优前,确认 JVM 已启用 NMT(如
-XX:NativeMemoryTracking=detail),再执行:jcmd <pid> VM.native_memory baseline</pid> - 进行参数调整(比如改了
-Xmx、-XX:MaxDirectMemorySize或线程池配置)并重启 JVM - 等服务稳定、负载接近原状后,执行:
jcmd <pid> VM.native_memory summary.diff scale=MB</pid>
输出中重点关注 reserved 和 committed 的变化量,尤其是 Thread、Class、Internal、Other 这几类——它们往往暴露非堆侧的真实膨胀点。
summary.diff 和 detail.diff 该怎么选
summary.diff 只显示各内存分类的总量差值,适合快速定位“哪块涨最多”;detail.diff 会列出每次 malloc/mmap 调用的增量,适合深挖具体是谁在分配、分配在哪(比如某个 native 方法反复申请 buffer)。
但要注意:
-
detail模式下,NMT 开销接近 10%,且内存占用本身会上升(tracking overhead 可达几十 MB),线上慎用 -
detail.diff输出极长,grep 时建议配合grep -A5 -B2 "Thread\|Direct\|Internal"快速聚焦 - 如果只关心“是否因调优减少了线程栈总开销”,
summary.diff完全够用;若要定位某第三方 SDK 的 native 分配泄漏,才值得切detail
为什么 diff 结果里 Thread 区暴涨却不一定是线程数变多
看到 - Thread (reserved=... +1200MB) 别急着去查线程 dump。线程内存 = 线程数 × 栈大小(-Xss),但 reserved 增量还可能来自:
- JVM 内部为 JIT 编译器、GC 线程、JFR 事件缓冲区等预分配的 arena 区域
- 某些 JDK 版本(如毕昇 JDK 在 aarch64 上)对线程栈的 mmap 保留策略更激进,即使未 commit 也计入 reserved
- 调优时若启用了
-XX:+UseContainerSupport但没设-XX:MaxRAMPercentage,容器内 JVM 可能误判可用内存,导致预留更多线程空间
验证方法:用 jstack <pid> | grep "java.lang.Thread" | wc -l</pid> 查真实线程数,再对比 jinfo -flag Xss <pid></pid> 算理论上限。如果两者乘积远小于 reserved 增量,说明问题不在用户线程本身。
别忽略 scale 和 elapsed time 的误导性
jcmd <pid> VM.native_memory summary.diff scale=MB</pid> 输出末尾通常带一句:NativeMemory Tracking: endtime is ..., elapsed time is 7 secs
这个 elapsed time 不是 JVM 运行时长,而是本次 NMT 数据采集耗时。它越长,说明当前 JVM 内存活动越频繁(比如 GC 正在大量移动对象、JIT 正在编译热点方法),此时 diff 结果反映的是“瞬时毛刺”,不是稳态差异。
可靠做法是:
- 在业务低峰期、GC 日志平稳(无 Full GC、Young GC 间隔 >30s)时做 baseline 和 diff
- 连续采样 2–3 次
summary.diff,看Thread、Class类别是否持续增长,而非单次跳变 - 如果 diff 中
GC或Code区波动剧烈,先暂停调优,检查是否 JIT 编译行为被参数改动意外触发
真正有效的调优对比,必须剥离 GC/JIT 的瞬时噪声,只看内存结构的稳态偏移。这点最容易被忽略,却直接决定你到底是在优化还是在干扰。


















