为何DirectByteBuffer的分配与回收成本更高?
DirectByteBuffer 分配与回收成本更高的原因解析
先纠正一个核心误解
你之前的认知有误:DirectByteBuffer 的实际内存并不是在 JVM GC 堆里,它的真实内存块是分配在操作系统的本地内存(Native Memory)中,JVM 堆里只存了一个很小的 DirectByteBuffer 对象,用来做引用句柄。这是理解成本差异的关键。
分配时的额外开销
调用 allocateDirect(int capacity) 时,底层要做这些事:
- 调用操作系统的内存分配函数(比如 Linux 用
malloc,Windows 用VirtualAlloc),从本地内存划一块连续区域。这个过程需要和操作系统内核交互,属于内核态系统调用,开销比 JVM 堆内的快速分配(比如 TLAB 分配)大得多。 - JVM 在堆里创建一个 DirectByteBuffer 对象,记录本地内存的地址、容量等元数据,同时绑定一个
Cleaner对象(负责后续的内存回收)。 - 有些场景下,JVM 还得给这块本地内存做初始化(比如清零),这也会多耗 CPU。
回收时的额外开销
DirectByteBuffer 的回收流程比堆内 Buffer 复杂很多:
- 当堆里的 DirectByteBuffer 对象被 GC 标记成垃圾后,不会直接释放本地内存,得等
ReferenceHandler线程处理对应的虚引用(Cleaner 是基于虚引用实现的)。 ReferenceHandler线程触发 Cleaner 的清理动作,调用操作系统的内存释放函数(比如free或VirtualFree),把本地内存还给操作系统。这个跨线程的异步处理,比堆内内存被 GC 直接回收的同步流程延迟更高、开销更大。- 如果本地内存占太多,JVM 可能会触发 Full GC 来强制清理没用的 DirectByteBuffer,而 Full GC 本身的开销就远大于 Young GC。
和堆内 ByteBuffer 的对比
堆内 ByteBuffer(比如 HeapByteBuffer)的内存直接来自 JVM 堆,分配时直接从 TLAB 或 Eden 区拿,回收时由 GC 直接处理,全程在 JVM 内部搞定,不用频繁和操作系统内核交互,所以分配回收成本更低。
内容的提问来源于stack exchange,提问作者light
相关产品推荐
相关产品推荐

