堆外内存释放间接依赖gc:gc只回收directbytebuffer对象,触发其cleaner执行freememory();若对象被强引用持有或gc不及时,将导致堆外内存泄漏;应显式调用cleaner.clean()并设置maxdirectmemorysize。

Java 堆外内存不直接受垃圾回收器(GC)管理,但它的释放间接依赖 GC 的触发机制。
简单说:堆外内存本身不是 GC 扫描和回收的对象,JVM 不会像清理堆内对象那样主动释放它;但它通过 Cleaner(虚引用 + 引用队列)与 GC 协作——只有当对应的 DirectByteBuffer 对象被 GC 判定为不可达时,Cleaner 才会被唤醒并执行 freeMemory() 释放底层内存。
这意味着:
- ✅ GC 不负责“直接回收”堆外内存,而是负责回收堆内的
DirectByteBuffer实例; - ✅
DirectByteBuffer被回收后,其关联的Cleaner任务才会运行,从而释放对应堆外空间; - ❌ 如果
DirectByteBuffer长期被强引用持有(比如缓存未清理、线程局部变量未清除),堆外内存就无法释放,造成泄漏; - ❌ GC 不及时(如堆内存充足、Full GC 少)、或
Cleaner执行被阻塞(如 Finalizer 线程积压),都会导致堆外内存堆积。
所以不能说“完全不受 GC 管理”,而应理解为:堆外内存的生命周期由堆内对象的可达性间接控制,释放时机不可控、有延迟、存在风险。
关键提醒:
- 不要依赖 GC 自动清理堆外内存来规避手动管理;
- 生产环境务必显式调用
cleaner.clean()(需反射或 Java 9+CleanerAPI),尤其在确定不再使用时; - 设置
-XX:MaxDirectMemorySize是必要防线,防止无节制分配导致 OOM。
补充说明:
JDK 9 起,sun.misc.Cleaner 已被 java.lang.ref.Cleaner 替代,新写法更安全、更可控,推荐优先使用标准 Cleaner API 而非反射。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











