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?
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).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).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.Where did you get that idea? It's not correct. Are you getting them mixed up with MappedByteBuffers?