JNI memory management using the Invocation API
c, java, java-native-interface, memory-management
Solution
There are a couple of strategies for reclaiming native resources (objects, file descriptors, etc.)
Invoke a JNI method during finalize() which frees the resource. Some people recommend against implementing finalize, and basically you can't really be sure that your native resource is ever freed. For resources such as memory this is probably not a problem, but if you have a file for example which needs to be flushed at a predictable time, finalize() probably not a good idea.
Manually invoke a cleanup method. This is useful if you have a point in time where you know that the resource must be cleaned up. I used this method when I had a resource which had to be deallocated before unloading a DLL in the JNI code. In order to allow the DLL to later be reloaded, I had to be sure that the object was really deallocated before attempting to unload the DLL. Using only finalize(), I would not have gotten this guaranteed. This can be combined with (1) to allow the resource to be allocated either during finalize() or at the manually called cleanup method. (You probably need a canonical map of WeakReferences to track which objects needs to have their cleanup method invoked.)
Supposedly the PhantomReference can be used to solve this problem as well, but I'm not sure exactly how such a solution would work.
Actually, I have to disagree with you on the JNI documentation. I find the JNI specification exceptionally clear on most of the important issues, even if the sections on managing local and global references could have been more elaborated.
Problem
When I'm building a java object using JNI methods, in order to pass it in as a parameter to a java method I'm invoking using the JNI invocation API, how do I manage its memory? Here's what I am working with: I have a C object that has a destructor method that is more complex that `free()`. This C object is to be associated with a Java object, and once the application is finished with the Java object, I have no more need for the C object. I am creating the Java object like so (error checking elided for clarity): ``` c_object = c_object_create (); class = (*env)->FindClass (env, "my.class.name"); constructor = (*env)->GetMethodID (env, class, "<init>", "(J)V"); instance = (*env)->NewObject (env, class, constructor, (jlong) c_object); method = (*env)->GetMethodID (env, other_class, "doSomeWork", "(Lmy.class.name)V"); (*env)->CallVoidMethod (env, other_class, method, instance); ``` So, now that I'm done with `instance`, what do I do with it? Ideally, I'd like to leave the garbage collection up to the VM; when it's done with `instance` it would be fantastic if it also called `c_object_destroy()` on the pointer I provided to it. Is this possible? A separate, but related question has to do with the scope of Java entities that I create in a method like this; do I have to manually release, say, `class`, `constructor`, or `method` above? The JNI doc is frustratingly vague (in my judgement) on the subject of proper memory management.