15

我知道分配directbytebuffer时,它不受垃圾收集的影响,但我想知道包装对象是否被垃圾收集。

例如,如果我分配了一个新的 DirectByteBuffer dbb,然后使用 dbb.duplicate() 复制(浅复制)它,我将在同一块内存周围有两个包装器。

这些包装器是否需要进行垃圾收集?如果我这样做了

while(true){
    DirectByteBuffer dbb2 = dbb.duplicate();
} 

我最终会自己OOM吗?

4

4 回答 4

18

在 Sun JDK 中,a java.nio.DirectByteBuffer—created by ByteBuffer#allocateDirect(int)— 有一个类型为 的字段sun.misc.Cleaner,它扩展了java.lang.ref.PhantomReference.

当 this Cleaner(记住,的子类型PhantomReference)被收集并即将进入关联ReferenceQueue时,运行在嵌套类型ReferenceHandler中的与收集相关的线程对实例进行特殊处理Cleaner:它向下转换并调用 on Cleaner#clean(),最终返回调用 on DirectByteBuffer$Deallocator#run(),而后者又调用 on Unsafe#freeMemory(long)。哇。

它相当迂回,我很惊讶Object#finalize()在游戏中没有看到任何用途。Sun 开发人员一定有他们的理由将其与收集和引用管理子系统联系得更紧密。

简而言之,你不会因为放弃对DirectByteBuffer实例的引用而耗尽内存,只要垃圾收集器有机会注意到放弃并且它的引用处理线程通过上述调用取得进展。

于 2011-07-14T19:40:23.347 回答
4

直接ByteBuffer对象就像任何其他对象一样:它可以被垃圾回收。

ByteBuffer对象被 GC 时,直接缓冲区使用的内存将被释放(这在 中没有明确说明ByteBuffer,但在 的文档中有所暗示MappedByteBuffer)。

有趣的地方是当你用直接缓冲区填充了虚拟内存空间,但堆中仍然有很多空间。事实证明(至少在 Sun JVM 上),在分配直接缓冲区时耗尽虚拟空间将触发 Java 堆的 GC。这可能会收集未引用的直接缓冲区并释放它们的虚拟内存承诺。

如果你在 64 位机器上运行,你应该使用-XX:MaxDirectMemorySize,它为你可以分配的缓冲区数量设置了一个上限(当你达到这个限制时也会触发 GC)。

于 2011-07-14T19:01:40.293 回答
1

查看DirectByteBuffer它的源代码只会返回一个新实例,所以不,您不会自己OOM。

只要您的代码的其余部分不保留对原始代码的引用,dbb那么该对象就会像往常一样被垃圾收集。dbb2当不再有对它们的任何引用时(即,while 循环的结尾),额外的对象同样会被垃圾回收。

于 2011-07-14T17:57:20.927 回答
-2

当分配一个直接字节缓冲区时,它不受垃圾回收的影响

你从哪里得到这个想法的?这是不正确的。您是否将它们与 MappedByteBuffers 混淆了?

于 2011-07-15T01:00:42.720 回答