在 Java 中,**直接内存(Direct Memory)**并不是 JVM 堆内存,而是通过 java.nio.ByteBuffer.allocateDirect() 或 Unsafe 等方式,直接向操作系统申请的一块堆外内存。它不受 JVM 垃圾回收直接管理,但需要特别注意“如何释放与管理”。
下面从 原理 → 管理方式 → 常见坑 → 最佳实践 系统说明。
特点
-Xmx 限制,但受 -XX:MaxDirectMemorySize 限制ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
buffer 是 堆里的 Java 对象直接内存不是 JVM GC 直接回收的,而是:
Java 对象被 GC → 触发 Cleaner → 释放堆外内存
DirectByteBuffer 内部有一个 CleanerDirectByteBuffer 被 GC 时Cleaner.clean() 调用 Unsafe.freeMemory()⚠️ 问题:
如果 Java 对象一直不 GC,堆外内存就不会释放!
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
buffer = null;
System.gc(); // 不保证立即回收
❌ 不可控
✅ 简单
ByteBufByteBuf buf = Unpooled.directBuffer(1024);
// 使用
buf.release(); // 显式释放
Netty 使用 引用计数:
retain() 增加引用release() 减少引用DirectByteBuffer(不推荐但可行)JDK 未提供公共 API,但可通过反射:
public static void clean(ByteBuffer buffer) throws Exception {
if (!buffer.isDirect()) return;
Method cleanerMethod = buffer.getClass().getMethod("cleaner");
cleanerMethod.setAccessible(true);
Object cleaner = cleanerMethod.invoke(buffer);
Method clean = cleaner.getClass().getMethod("clean");
clean.setAccessible(true);
clean.invoke(cleaner);
}
⚠️ 不跨版本稳定
ByteBuf buf = PooledByteBufAllocator.DEFAULT.directBuffer(1024);
✅ 减少分配/释放
✅ 降低 GC 压力
✅ 高性能
-XX:MaxDirectMemorySize=512m
默认 ≈ 堆最大值
jstat -gc <pid>
或
NMT (Native Memory Tracking)
-XX:NativeMemoryTracking=detail
while (true) {
ByteBuffer.allocateDirect(1MB);
}
→ 堆外内存爆炸
ByteBuf buf = ...;
// 没 release
→ 直接内存泄漏
buffer = null;
// 不一定立刻释放
✅ 使用 Netty / 池化
✅ 明确释放责任(who allocates, who releases)
✅ 控制 MaxDirectMemorySize
✅ 不要频繁 allocateDirect
✅ 使用 NMT 监控
如果你愿意,我可以:
你更想深入哪一块?
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。