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