Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>There is no leak.</p> <p><code>ByteBuffer.allocateDirect()</code> allocates memory from the native heap / free store (think <code>malloc()</code>) which is in turn wrapped in to a <code>ByteBuffer</code> instance.</p> <p>When the <code>ByteBuffer</code> instance gets garbage collected, the native memory is reclaimed (<em>otherwise you would leak native memory</em>).</p> <p>You're calling <code>System.gc()</code> in hope the native memory is reclaimed <em>immediately</em>. However, <strong>calling <code>System.gc()</code> is only a request</strong> which explains why your second log statement doesn't tell you memory has been released: it's because it hasn't yet!</p> <p>In your situation, there is apparently enough free memory in the Java heap and the garbage collector decides to do nothing: as a consequence, unreachable <code>ByteBuffer</code> instances are not collected yet, their finalizer is not run and native memory is not released.</p> <p>Also, keep in mind this <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4857305">bug</a> in the JVM (not sure how it applies to Dalvik though) where heavy allocation of direct buffers leads to unrecoverable <code>OutOfMemoryError</code>.</p> <hr> <p>You commented about doing controlling things from JNI. This is actually possible, you could implement the following:</p> <ol> <li><p>publish a <code>native ByteBuffer allocateNative(long size)</code> entry point that:</p> <ul> <li>calls <code>void* buffer = malloc(size)</code> to allocate native memory</li> <li>wraps the newly allocated array into a <code>ByteBuffer</code> instance with a call to <code>(*env)-&gt;NewDirectByteBuffer(env, buffer, size);</code></li> <li><strike>converts the <code>ByteBuffer</code> local reference to a global one with <code>(*env)-&gt;NewGlobalRef(env, directBuffer);</code></strike></li> </ul></li> <li><p>publish a <code>native void disposeNative(ByteBuffer buffer)</code> entry point that:</p> <ul> <li>calls <code>free()</code> on the direct buffer address returned by <code>*(env)-&gt;GetDirectBufferAddress(env, directBuffer);</code></li> <li><strike>deletes the global ref with <code>(*env)-&gt;DeleteGlobalRef(env, directBuffer);</code></strike></li> </ul></li> </ol> <p>Once you call <code>disposeNative</code> on the buffer, you're not supposed to use the reference anymore, so it could be very error prone. Reconsider whether you really need such explicit control over the allocation pattern.</p> <hr> <p><strong>Forget what I said about global references. Actually global references are a way to store a reference in native code (like in a global variable) so that a further call to JNI methods can use that reference. So you would have for instance:</strong></p> <ul> <li><strong>from Java, call native method <code>foo()</code> which creates a global reference out of a local reference (obtained by creating an object from native side) and stores it in a native global variable (as a <code>jobject</code>)</strong></li> <li><strong>once back, from Java again, call native method <code>bar()</code> which gets the <code>jobject</code> stored by <code>foo()</code> and further processes it</strong></li> <li><strong>finally, still from Java, a last call to native <code>baz()</code> deletes the global reference</strong></li> </ul> <p>Sorry for the confusion.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload