views:

706

answers:

3

I have a memory leak that I have isolated to incorrectly disposed direct byte buffers.

ByteBuffer buff = ByteBuffer.allocateDirect(7777777)

The GC collects the objects that harbor these buffers but does not dispose of the buffer itself. If I instantiate enough of the transient objects containing buffers I get this encouraging message.

java.lang.OutOfMemoryError: Direct buffer memory

I have been searching up this problem and apparently

buff.clear

and

 System.gc()

does not work

+4  A: 

I suspect that somewhere your application has a reference to the ByteBuffer instance(s) and that is preventing it from being garbage collected.

The buffer memory for a direct ByteBuffer is allocated outside of the normal heap (so that the GC doesn't move it!!). However, the ByteBuffer API provides no method for explicitly disposing of / deallocating a buffer. So I assume that the garbage collector will do it ... once it determines that the ByteBuffer object is no longer referenced.

Stephen C
+5  A: 

The ByteBuffer documentation says:

A direct byte buffer may be created by invoking the allocateDirect factory method of this class. The buffers returned by this method typically have somewhat higher allocation and deallocation costs than non-direct buffers. The contents of direct buffers may reside outside of the normal garbage-collected heap, and so their impact upon the memory footprint of an application might not be obvious. It is therefore recommended that direct buffers be allocated primarily for large, long-lived buffers that are subject to the underlying system's native I/O operations. In general it is best to allocate direct buffers only when they yield a measureable gain in program performance.

In particular, the statement "may reside outside of the normal garbage-collected heap" seems relevant to your example.

Greg Hewgill
+2  A: 

The allocated memory is realized through a native libary. This memory will be freed when the ByteBuffer#finalize method is called, iaw when the Buffer is gc'd. Have a look at the allocate() and finalize() implementations of DirectByteBufferImpl.

buff.clear() is not necessary, System.gc() will only help if, like others already mentioned, there's no more reference left to the ByteBuffer object.

Andreas_D
My guess is that System.gc won't help in ANY case. I would expect that the "event" of not having enough buffer memory would trigger a GC in an attempt to free up old buffers. The OOM exception is only thrown when there's not enough buffer memory ... after the GC.
Stephen C