direct buffer memory溢出本质是directbytebuffer持续占用本地内存且未释放,超出隐式上限(默认≈-xmx),不走gc、工具不可见,依赖脆弱cleaner机制,需-nmt或jfr监控。

Java 中 Direct buffer memory 溢出本质是堆外内存失控,不是 GC 能管的范围,定位要绕开堆内视角,释放不能只靠等 GC —— 关键在主动干预和资源生命周期管理。
定位:先确认是不是堆外内存问题
看到 java.lang.OutOfMemoryError: Direct buffer memory 时,别急着加堆内存。先排除堆内泄漏:
- 用
jmap -heap <pid></pid>查堆使用率,若远低于设置值(比如 -Xmx2g,但实际只用了 800MB),基本可排除堆溢出 - 用
jstat -gc <pid></pid>观察 Young GC / Full GC 频次和耗时,GC 正常但内存持续上涨,指向堆外 - 开启 Native Memory Tracking(NMT):
-XX:NativeMemoryTracking=summary启动 JVM,再用jcmd <pid> VM.native_memory summary.diff</pid>对比 baseline,重点关注Internal或Direct项是否异常增长
定位:查清谁在分配 DirectBuffer
多数情况不是手写 allocateDirect(),而是框架隐式使用:
- Netty 默认用
PooledByteBufAllocator管理 DirectBuffer;若未配置或连接未正确关闭,缓冲区会堆积 - 检查是否设置了
-Dio.netty.maxDirectMemory,没设则默认等于-Xmx值,容易掩盖问题 - 用
jstack <pid></pid>结合业务日志,看高负载时哪些线程频繁调用PlatformDependent.allocateDirectNoCleaner或Unsafe.allocateMemory - 若有自定义 NIO 通信模块,重点 review 连接断开时是否调用了
buffer.clear()、buffer = null,但更关键的是确保 Channel/Connection 被真正 close
释放:避免依赖 Cleaner 的被动回收
DirectBuffer 对象被 GC 后,底层内存靠 Cleaner 异步清理,延迟不可控。生产环境需主动干预:
- 对明确创建的 DirectBuffer,用完立即调用
cleaner.clean()(通过反射):
public static void cleanDirectBuffer(ByteBuffer buffer) {
if (buffer != null && buffer.isDirect()) {
try {
Field cleanerField = buffer.getClass().getDeclaredField("cleaner");
cleanerField.setAccessible(true);
Object cleaner = cleanerField.get(buffer);
if (cleaner != null) {
cleaner.getClass().getMethod("clean").invoke(cleaner);
}
} catch (Exception ignored) {}
}
}- Netty 场景下,优先使用
Unpooled.directBuffer()+ 显式.release(),或确保 Pooled 分配器的ByteBuf在 finally 块中 release - 不要仅靠
buffer = null或System.gc()—— 后者不保证触发 Cleaner,且影响性能
预防:从配置与设计层面堵漏
治标更要治本:
- JVM 启动加参数:
-XX:MaxDirectMemorySize=512m(建议设为略高于业务峰值,如 Netty 实际用量的 1.5 倍),让 OOM 提前暴露,而非耗尽容器内存被 kill - Netty 初始化时显式指定内存限制:
new PooledByteBufAllocator(true, 1, 1, 8192, 11, 0, 0, ConcurrentLinkedQueue::new, false, true, 512 * 1024 * 1024) - 连接管理必须成对:connect ↔ close、alloc ↔ free、subscribe ↔ unsubscribe,用 try-with-resources 或 try-finally 封装资源生命周期
- 监控项加入
sun.nio.ch.DirectBuffer.count(通过 JMX),或定期采集NativeMemoryTracking数据趋势
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











