views:

562

answers:

2

I want to allocate some memory in C and keep it associated with a java object instance, like this:

void configure(JNIEnv *object, jobject obj, ....) {
  char *buf = new char[1024];
  // associated <buf> with <obj> somehow
}

And then later free the memory when the java object gets garbage collected - I could do this by calling a JNI function from the finalize() method of the java object.

The question is, how do I associate a C pointer with the java object? Keep a long field in the object and cast the pointer to long? Is there a better way?

A: 

Java doesn't have any concept of native pointer, so storing it as a long is the only real option. But you should not rely on finalize to free the pointer; the finalize method is unreliable as a means of cleaning up resources. See this question for further details.

JesperE
+4  A: 

Generally, if you want to transfer a pointer from C to Java, it's recommended to use long so that there are enough bits to hold the pointer value in case the platform is 64 bits.

Then, have a look at ByteBuffer.allocateDirect() which creates a ByteBuffer instance which memory can be shared with C. You can allocate such a direct ByteBuffer from the Java side then pass it as a jobject to a JNI function and inside this JNI function you use the GetDirectBufferAddress function.

Another way is to wrap a native area of memory with the NewDirectByteBuffer JNI function from the native side. It gives you a jobject you pass back to the Java side (pay attention to local and global references). Pay attention to the fact that once the direct ByteBuffer that wraps the native memory has been created, you are still responsible for managing the native memory: at some point, you will have to call delete buf; in your native code, Java won't do it for you.

Gregory Pakosz
Thanks! If I understand correctly, using ByteBuffer.allocateDirect() sidesteps the pointer passing + memory management; this way ByteBuffer manages the memory.
Viktor
Allocating the direct ByteBuffer from the Java side let Java allocate the block of memory, which is going to be released when `finalize` runs. The only downside is that you don't exactly know when the garbage collector passes so you don't really know when the memory is released apart that it's going to be released after you're finished with the buffer.
Gregory Pakosz
+1 Neat! Good answer.
JesperE