Java DirectByteBuffer 包装器是否会被垃圾回收?
我知道当分配 directbytebuffer 时,它不会受到垃圾收集,但我想知道包装对象是否被垃圾收集。
例如,如果我分配一个新的 DirectByteBuffer dbb,然后使用 dbb.duplicate() 对其进行复制(浅复制),那么我将在同一块内存周围有两个包装器。
这些包装器是否会受到垃圾收集?如果我这样做,
while(true){
DirectByteBuffer dbb2 = dbb.duplicate();
}
我最终会 OOM 吗?
I understand that when a directbytebuffer is allocated, its not subject to garbage collection, but what I'm wondering is if the wrapping object is garbage collected.
For example, if I allocated a new DirectByteBuffer dbb, and then duplicated(shallow copied) it using dbb.duplicate(), I'd have two wrappers around the same chunk of memory.
Are those wrappers subject to garbage collection? If I did
while(true){
DirectByteBuffer dbb2 = dbb.duplicate();
}
Would I eventually OOM myself?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在 Sun JDK 中,
java.nio.DirectByteBuffer
— 由ByteBuffer#allocateDirect(int)
— 有一个sun.misc.Cleaner
类型的字段,它扩展了java.lang.ref.PhantomReference
。当此
Cleaner
(请记住,PhantomReference
的子类型)被收集并即将移入关联的ReferenceQueue
时,与收集相关的线程将运行通过嵌套类型ReferenceHandler
对Cleaner
实例进行特殊处理:它向下转换并调用Cleaner#clean()
,最终使其方式回到调用DirectByteBuffer$Deallocator#run()
,它又调用Unsafe#freeMemory(long)
。哇。这是相当迂回的,我很惊讶没有看到任何
Object#finalize()
的使用。 Sun 开发人员一定有他们的理由将其与收集和引用管理子系统联系得更紧密。简而言之,只要垃圾收集器有机会注意到放弃并且其引用处理线程通过调用取得进展,您就不会因放弃对 DirectByteBuffer 实例的引用而耗尽内存如上所述。
In the Sun JDK, a
java.nio.DirectByteBuffer
—created byByteBuffer#allocateDirect(int)
—has a field of typesun.misc.Cleaner
, which extendsjava.lang.ref.PhantomReference
.When this
Cleaner
(remember, a subtype ofPhantomReference
) gets collected and is about to move into the associatedReferenceQueue
, the collection-related thread running through the nested typeReferenceHandler
has a special case treatment ofCleaner
instances: it downcasts and calls onCleaner#clean()
, which eventually makes its way back to calling onDirectByteBuffer$Deallocator#run()
, which in turn calls onUnsafe#freeMemory(long)
. Wow.It's rather circuitous, and I was surprised to not see any use of
Object#finalize()
in play. The Sun developers must have had their reasons for tying this in even closer to the collection and reference management subsystem.In short, you won't run out of memory by virtue of abandoning references to
DirectByteBuffer
instances, so long as the garbage collector has a chance to notice the abandonment and its reference handling thread makes progress through the calls described above.直接的 ByteBuffer 对象就像任何其他对象一样:它可以被垃圾收集。
当
ByteBuffer
对象被 GC 时,直接缓冲区使用的内存将被释放(这对于ByteBuffer
没有明确说明,但在的文档中隐含了>MappedByteBuffer
)。事情变得有趣的是,当您用直接缓冲区填充了虚拟内存空间,但堆中仍然有大量空间时。事实证明(至少在 Sun JVM 上),分配直接缓冲区时虚拟空间耗尽将触发 Java 堆的 GC。这可能会收集未引用的直接缓冲区并释放其虚拟内存承诺。
如果您在 64 位计算机上运行,则应该使用 -XX:MaxDirectMemorySize,它对您可以分配的缓冲区数量设置了上限(并且当您达到该上限时也会触发 GC)限制)。
A direct
ByteBuffer
object is just like any other object: it can be garbage-collected.The memory used by a direct buffer will be released when the
ByteBuffer
object is GC'd (this is not explicitly stated forByteBuffer
, but is implied by the documentation ofMappedByteBuffer
).Where things get interesting is when you've filled your virtual memory space with direct buffers, but still have lots of room in the heap. It turns out that (at least on the Sun JVM), running out of virtual space when allocating a direct buffer will trigger a GC of the Java heap. Which may collect unreferenced direct buffers and free their virtual memory commitment.
If you're running on a 64-bit machine, you should use
-XX:MaxDirectMemorySize
, which puts an upper limit on the number of buffers that you can allocate (and also triggers GC when you hit that limit).查看 DirectByteBuffer 的源代码,它只是返回一个新实例,所以不,您自己不会 OOM。
只要代码的其余部分不保留对原始
dbb
的引用,那么该对象就会像平常一样被垃圾收集。当不再有任何对它们的引用时(即 while 循环结束),额外的 dbb2 对象将类似地被垃圾收集。Looking at the source code to
DirectByteBuffer
it just returns a new instance, so no, you won't OOM yourself.As long as the rest of your code doesn't hold onto a reference to the original
dbb
then that object will get garbage collected as normal. The extradbb2
objects will similarly get garbage collected when there is no longer any reference to them(ie, the end of the while loop).Java 对象和本机内存都被垃圾收集器同时释放。
但是,请注意,由于垃圾收集器在清理直接缓冲区方面效果不佳,因此最好分配和重用长期存在的直接缓冲区,而不是创建和放弃新的直接缓冲区。
Both the Java object and the native memory are freed at the same time by the garbage collector.
However, note that because the garbage collector doesn’t work well at cleaning up direct buffers, it’s best to allocate and reuse long-lived direct buffers instead of creating and abandoning new ones.
你从哪里得到这个想法的?这是不正确的。您是否将它们与 MappedByteBuffers 混淆了?
Where did you get that idea? It's not correct. Are you getting them mixed up with MappedByteBuffers?