Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are Java DirectByteBuffer wrappers garbage collected?

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?

like image 957
Li Pi Avatar asked Jul 14 '11 17:07

Li Pi


3 Answers

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.

like image 75
seh Avatar answered Oct 18 '22 03:10

seh


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).

like image 39
parsifal Avatar answered Oct 18 '22 04:10

parsifal


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).

like image 1
agxs Avatar answered Oct 18 '22 03:10

agxs