2

When I return a direct ByteBuffer to JNI, how long until it can get reclaimed by the JVM/GC?

Suppose I have a function like this:

void* func()
{
  [ ... ]
  jobject result = env->CallStaticObjectMethod(testClass, doSomethingMethod);
  void* pointerToMemory = env->GetDirectBufferAddress(result);
  return pointerToMemory;

}

The JVM can't possibly know how long I'm going to use that pointerToMemory, right? What if I want to hold on to that address and the corresponding memory for a while?

Suppose I want to circumvent this issue and return a byte[] from Java to JNI like this:

ByteBuffer buf;
byte[] b = new byte[1000];
buf = ByteBuffer.wrap(b);
buf.order(ByteOrder.BIG_ENDIAN); 

return buf.array();

AND THEN do the same as above, I store a pointer to that byte[] and want to hold on to it for a while. How / when / why is the JVM going to come after that backing byte[] from Java?

void* function()
{
  jbyteArray byteArr = (jbytearray)env->CallStaticObjectMethod(testClass, doSomethingMethod);
  jbyte *b= env->GetByteArrayElements(byteArr, 0);  
  return b;
}
Blub
  • 13,014
  • 18
  • 75
  • 102

1 Answers1

1

The short answer is: If the function implements a native method, the pointer will be invalid as soon as you return.

To avoid this, you should get a global reference for all objects that you intend to keep valid after returning. See the documentation on local and global references for more information.

To understand better how JNI manages references from native code, see the documentation on PushLocalFrame/PopLocalFrame.

jop
  • 2,226
  • 15
  • 16
  • Suppose the second szenario I posted: I return a byte[] from Java. It will get copied, right? How do I know when things get copied? Is there documentation somewhere that tells me that the byte[] will be copied? I just assume it does, because there is a ReleaseByteElements() function. But here is the most important thing: Can I use free() instead of the ReleaseByteElements() call? – Blub Mar 01 '13 at 12:21
  • Not necessarily. If you look into the documentation, the third parameter (`isCopy`) to `GetByteArrayAlElements` tells you if it has been copied. But you shouldn't assume that you can use `free()`. It might work with some version of the JVM, but break in the future or in other JVMs. Stick to the API. – jop Mar 01 '13 at 12:31
  • 1
    jop, do you know that if I do NewDirectByteBuffer(b) where b is malloc'ed memory in C, is the JVM going to try and touch and delete it? If not, I think the safest option for me, is to make a JNI call like in this link, that way I have full control over my memory and can free it in C whenever I want. http://stackoverflow.com/questions/5060307/bytebuffer-not-releasing-memory The only remaining worry for me, is that I'm going to run into this JVM bug, because I do need many of these buffers. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4857305 Is there maybe a way to do all this with byte[] – Blub Mar 01 '13 at 12:49
  • I think the best solution may be to simply copy everything out manually from the direct buffer address that I get from the buffer that I created in Java. That way the Java GC leaves me alone, and I can free the memory however I please. So I just hope that this DirectBuffer bug got fixed in 1.6 or 1.7. Would piss me off a lot if not :/ – Blub Mar 01 '13 at 13:03