arthas 不直接监控堆外内存,需结合 jvm 的 nmt 和系统工具定位泄漏;先通过 rss 与堆内存对比确认问题,再用 nmt 分类分析,配合 arthas 监控 directbytebuffer 等操作,最后用 gdb、perf 等深入验证。

Arthas 本身不直接监控堆外内存,但它能辅助定位堆外内存泄漏的线索;真正要查堆外内存,得靠 JVM 自带的 NMT(Native Memory Tracking)配合系统级工具。关键不是“用 Arthas 查堆外”,而是“用 Arthas 锁定可疑行为,再用 NMT 和底层工具确认堆外增长源头”。
先看堆外是否真在涨
别急着上工具,先确认问题存在:
- 用 top -p
或 ps aux --sort=-%mem | head -10 看 Java 进程 RSS(常驻内存)是否持续上升,而堆内(heap)使用率稳定甚至偏低——这是堆外泄漏的典型信号 - 执行 arthas memory,重点关注 non-heap usage(非堆)部分:它只显示 metaspace + code cache,不包括 DirectByteBuffer、JNI、线程栈等真实堆外内存,所以这里数值小 ≠ 没问题
- 对比 jstat -gc
的堆内存趋势和 cat /proc/ /status | grep VmRSS 的实际物理内存,差值大的时候,堆外嫌疑就高
启用 NMT 获取 JVM 堆外内存分类视图
NMT 是 JVM 官方支持的堆外内存统计机制,必须重启生效,但信息最权威:
- 在 JVM 启动参数中添加:-XX:NativeMemoryTracking=detail(推荐 detail,summary 太粗略)
- 重启应用后,用 jcmd
VM.native_memory summary 查整体分布(如 Internal、Direct buffer、Thread、Code、GC 等各占多少) - 如果发现 Internal 或 Direct buffer 持续增长,基本可锁定方向;再用 jcmd
VM.native_memory detail.diff 对比两次快照,看哪些调用路径申请最多 - 注意:NMT 有 5%~10% 性能开销,生产环境建议只在排查期开启,问题定位后关闭
用 Arthas 辅助定位堆外操作热点
Arthas 不查堆外内存本身,但能帮你找到谁在频繁申请 DirectByteBuffer 或 JNI 资源:
- 监控 DirectByteBuffer 构造:watch java.nio.DirectByteBuffer '
' '{params}' -x 2 ,看是否有大量 new 调用且没被释放 - 查当前存活的 DirectByteBuffer 实例数:vmtool --action getInstances --className java.nio.DirectByteBuffer --express 'instances.length'
- 搜索可能使用堆外资源的类:sc -d *Netty* *nio* *Unsafe*,重点检查 Netty 的 PooledByteBufAllocator、MappedByteBuffer 使用逻辑
- 结合 thread -n 5 看高 CPU 或长时间运行的线程,再用 thread
查栈,确认是否在做文件映射、零拷贝或 JNI 调用
必要时深入系统层验证
当 NMT 显示某类堆外内存异常,但代码逻辑不明显时,需进一步验证:
- 用 gdb -p
附加进程,执行 info proc mappings 查大块匿名内存段([anon]),再结合 cat /proc/ /maps | awk '$6 ~ /^\[anon\]$/ {sum += $3-$1} END {print sum/1024 " MB"}' 统计总量 - 若怀疑是 native 代码泄漏(如 JNI),可用 gperftools(tcmalloc)配合 pprof 分析 malloc/free 调用栈,前提是提前注入 LD_PRELOAD
- 对 mmap/munmap 频繁的场景,可尝试 perf record -e syscalls:sys_enter_mmap,syscalls:sys_enter_munmap -p
抓系统调用,再用 perf script 分析配对情况
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











