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?
In the Sun JDK, a java.nio.DirectByteBuffer
—created by ByteBuffer#allocateDirect(int)
—has a field of type sun.misc.Cleaner
, which extends java.lang.ref.PhantomReference
.
When this Cleaner
(remember, a subtype of PhantomReference
) gets collected and is about to move into the associated ReferenceQueue
, the collection-related thread running through the nested type ReferenceHandler
has a special case treatment of Cleaner
instances: it downcasts and calls on Cleaner#clean()
, which eventually makes its way back to calling on DirectByteBuffer$Deallocator#run()
, which in turn calls on Unsafe#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.
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 for ByteBuffer
, but is implied by the documentation of MappedByteBuffer
).
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).
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 extra dbb2
objects will similarly get garbage collected when there is no longer any reference to them(ie, the end of the while loop).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With