direct buffer 释放滞后会触发 full gc,因其依赖 cleaner 和 phantomreference 异步清理,而 cleaner 是堆内对象需 gc 发现不可达才入队,且 cleanerthread 单线程低优先级无背压,导致 native 内存长期不释放,jvm 为保稳主动触发 full gc 扫描关联对象。

直接内存(Direct Buffer)本身不归堆内存GC管理,但它的释放滞后可能间接触发 Full GC——这不是因为直接内存占用了堆空间,而是因为它背后持有的物理资源(如 native memory)未及时释放,导致 JVM 为保障稳定性主动发起 Full GC 来尝试回收关联的 Cleaner 或 PhantomReference 链,进而牵连老年代扫描与停顿。
为什么 Direct Buffer 释放会拖慢、甚至触发 Full GC
Java 中通过 ByteBuffer.allocateDirect() 分配的内存位于堆外,由系统本地内存承载。JVM 不直接跟踪其生命周期,而是依赖 Cleaner(JDK 9+)或 sun.misc.Cleaner(JDK 8)配合 PhantomReference 实现异步清理。这个过程存在天然延迟:
- Cleaner 对象本身是堆内对象,需等待 GC 发现其不可达后才入队;
- Cleaner 的执行线程(
java.lang.ref.Cleaner$CleanerThread)是单线程、低优先级,且无背压机制; - free() 回调逻辑——只要 Cleaner 没执行,native memory 就不释放,JVM 可能因 Native OOM 风险感知 主动触发 Full GC,试图加速 Cleaner 入队与执行。
如何确认是 Direct Buffer 引发的间接 Full GC
不能只看堆内存曲线,要交叉验证三类线索:
- GC 日志中出现 “System.gc()” 或 “Ergonomics” 触发源:说明 JVM 主动干预,常见于 NativeMemoryTracking(NMT)检测到直接内存接近上限;
-
使用 -XX:NativeMemoryTracking=detail 启用 NMT,运行 jcmd
VM.native_memory summary scale=MB,重点关注 Internal 和 Other 区域持续增长,尤其 Internal 中 Cleaner 或 DirectBuffer 相关计数飙升; - 堆 dump 中大量 sun.misc.Cleaner 或 java.lang.ref.Cleaner 实例,且 dominator tree 显示它们被 ReferenceQueue 长期持有,或自身 retain heap 较大(说明关联的 DirectByteBuffer 尚未真正释放);
-
top -H -p
观察 CleanerThread CPU 占用异常高 ,或 jstack 发现该线程长时间处于 RUNNABLE 状态但无实际清理进展(常因 native free() 被阻塞,如磁盘 IO、锁竞争)。
排查与缓解的关键操作
重点不是“等它自己清”,而是打破 Cleaner 积压链并降低物理释放延迟:
- 强制触发 Cleaner 执行:
jcmd <pid> VM.run_finalization</pid>(临时缓解,不推荐生产常用); - 升级并启用 JDK 17+ 的 ZGC 或 Shenandoah:它们支持并发处理 Reference processing,大幅缩短 Cleaner 入队到执行的延迟;
- 代码层显式调用 Buffer.clear() + System.runFinalization() 不可靠,应改用 Buffer.cleaner().clean()(需反射访问,仅限 JDK 8–13)或更稳妥的 Buffer.asReadOnlyBuffer().clear() 配合池化复用;
- 对 Netty 等框架,检查是否启用了 -Dio.netty.noPreferDirect=true 或调整 PooledByteBufAllocator 的
maxOrder和chunkSize,减少小块 Direct Buffer 创建频次; - 监控层面接入 NMT + JFR(Java Flight Recorder),录制事件
jdk.DirectBufferAllocation和jdk.CleanerRegistration,定位高频分配点。
本质上,这不是 GC 算法的问题,而是堆外资源与堆内引用生命周期错配的结果。查清楚 Cleaner 是否积压、Direct Buffer 是否复用不足、native free 是否被阻塞,比调大堆内存更治本。











