arthas是排查java nio堆外内存泄露的有效工具,核心是定位directbytebuffer创建与未释放路径,结合rss增长、nmt分析、cleaner引用链及业务线程追踪确认泄露源头。

Java NIO 堆外内存泄露排查,Arthas 是非常有效的工具。核心思路是:定位 DirectByteBuffer 对象的创建与未释放路径,结合堆外内存增长趋势、GC 行为和 native 内存映射,快速缩小问题范围。
确认是否真是堆外内存泄露
先排除误判:
- 用 jstat -gc
观察 Old GC 频率和 Metaspace 使用量,堆内正常但进程 RSS 持续上涨(top -p 看 RES 列),才倾向堆外泄露 - 用 cat /proc/
/smaps | grep -i "size.*kb" | awk '{sum+=$2} END{print sum/1024 " MB"}' 查总虚拟内存;重点关注 Anonymous 和 DirectMap 区域(JDK 11+ 可看DirectMap*) - JDK 8u262+ 可开启 -XX:NativeMemoryTracking=detail,再用 jcmd
VM.native_memory summary 对比 baseline,看Internal或Other是否异常增长(NIO DirectBuffer 归属Internal类别)
用 Arthas 监控 DirectByteBuffer 分配
Arthas 的 watch 和 trace 能捕获关键构造点:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 监控
java.nio.DirectByteBuffer.<init></init>构造器(注意 JDK 版本:JDK 9+ 是java.nio.Bits.reserveMemory触发分配) - 执行:
watch java.nio.DirectByteBuffer'{params, returnObj}' -x 3 -n 5
查看每次分配的 size 和调用栈,高频小 size 分配可能来自未复用的 ByteBuffer - 若使用 Netty,更应 trace
io.netty.buffer.PoolArena.allocate或Unpooled.directBuffer()
查找未清理的 Cleaner 引用链
DirectByteBuffer 依赖 Cleaner 回收,泄露常因 Cleaner 未触发或被强引用阻塞:
- 用 Arthas
vmtool查存活的 Cleaner 实例:
vmtool --action getInstances --className sun.misc.Cleaner --limit 10 - 对任一 Cleaner 实例,查看其 referent(即关联的 DirectByteBuffer):
vmtool --action getStaticField --className sun.misc.Cleaner --fieldName queue
(更实用的是用ognl查具体对象的cleaner.clean()是否可手动触发,但生产环境慎用) - 结合
heapdump(dashboard或heapdump /tmp/dump.hprof)后用 MAT 打开,按java.nio.DirectByteBuffer排序,看 dominated heap 是否巨大,并检查其cleaner字段是否为 null(说明已注册)或非 null 但cleaner.heap为 true(说明未注册,可能被包装)
结合线程与业务逻辑定位源头
分配本身不是问题,未释放才是根源:
- 用
thread -n 10查 CPU 或阻塞线程,重点关注 NIO 线程(如 Netty EventLoop)是否卡在 write/read,导致 buffer 无法 release - 对可疑业务方法(如自定义编解码器、文件传输 handler),用
trace追踪 buffer 创建 → 使用 →buffer.clear()/buffer.release()全流程 - 特别注意:
ByteBuffer.allocateDirect()后忘记调用cleaner.clean()(不推荐手动调)、或把 buffer 存入静态集合长期持有、或在 CompletableFuture 异步流中丢失 release 调用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










