据我所知,当分配一个directbytebuffer时,它不受垃圾收集的影响,但我想知道的是包装对象是否被垃圾收集。
例如,如果我分配了一个新的DirectByteBuffer dbb,然后使用dbb.duplicate()复制(浅层复制)它,我会在同一块内存周围有两个包装器。
这些包装器是否需要进行垃圾回收?如果我做了
while(true){
DirectByteBuffer dbb2 = dbb.duplicate();
}
我最终会自己OOM吗?
答案 0 :(得分:12)
在Sun JDK中,由ByteBuffer#allocateDirect(int)
创建的java.nio.DirectByteBuffer
有一个sun.misc.Cleaner
类型的字段,其范围为java.lang.ref.PhantomReference
。
当此Cleaner
(请记住,PhantomReference
的子类型)被收集并即将进入关联的ReferenceQueue
时,与集合相关的线程将运行嵌套类型{{ 1}}对ReferenceHandler
个实例进行了特殊处理:它向下转发并调用Cleaner
,最终回到调用Cleaner#clean()
,然后DirectByteBuffer$Deallocator#run()
调用Unsafe#freeMemory(long)
}}。哇。
这是相当迂回的,我很惊讶在游戏中没有看到Object#finalize()
的使用。 Sun开发人员必须有理由将其与更接近集合和参考管理子系统联系起来。
简而言之,只要垃圾收集器有机会注意到放弃并且其引用处理线程通过调用进行,您就不会因放弃对DirectByteBuffer
实例的引用而耗尽内存。如上所述。
答案 1 :(得分:3)
直接ByteBuffer
对象就像任何其他对象一样:它可以被垃圾收集。
当ByteBuffer
对象是GC时,将释放直接缓冲区使用的内存(ByteBuffer
没有明确说明,但MappedByteBuffer
的文档暗示了这一点。 )。
当事情变得有趣的时候,你用直接缓冲区填充你的虚拟内存空间,但堆中仍有很多空间。事实证明(至少在Sun JVM上),在分配直接缓冲区时耗尽虚拟空间将触发Java堆的GC。这可能会收集未引用的直接缓冲区并释放其虚拟内存承诺。
如果您在64位计算机上运行,则应使用-XX:MaxDirectMemorySize
,它会为您可以分配的缓冲区数量设置上限(并在达到该限制时触发GC)。
答案 2 :(得分:1)
查看DirectByteBuffer
的源代码,它只返回一个新实例,所以不,你不会自己OOM。
只要代码的其余部分没有保留对原始dbb
的引用,那么该对象将正常收集垃圾。额外的dbb2
对象同样会在不再引用它们时(即while循环的结束)收集垃圾。
答案 3 :(得分:-2)
当分配directbytebuffer时,它不受垃圾的影响 集合
你从哪里得到这个想法?这不对。你是否将它们与MappedByteBuffers混淆了?