Sunday February 19, 2006 I've been writing a JNI wrapper that requires the creation of a native thread and I've set things up using a JNI_OnLoad() function to initialise the DLL and create an event handling thread thread. I also used the JNI_OnUnload() function to kill the thread and clean up the DLL, but what was puzzling me was that although JNI_OnLoad() was being called OK, JNI_OnUnload() was never being called, and because the thread was attached to the JVM via a call to AttachCurrentThread(), the JVM would never exit as it still had an active thread. A simple workaround was to attach the thread to the JVM as a daemon thread using AttachCurrentThreadAsDaemon as daemon threads don't keep the JVM alive, but that still meant the DLL wasn't being cleaned up properly.
Google revealed a post on the Java Forums which explained that the ClassLoader was keeping a reference to the class containing the native code wrapping the DLL, and that was preventing the JNI_OnUnload() function from being called. The post also explains that if you make a call to System.runFinalizersOnExit() then the finalizer for the ClassLoader will be called on exit and that in turn will call the native code's JNI_OnUnload() method, and a simple experiment proves that is indeed the case. However the System.runFinalizersOnExit() method is deprecated:
In light of this it appears that although JNI_OnLoad() is useful, JNI_OnUnload() is less than useful. There is a workaround, which is to register a native exit callback using Runtime.addShutdownHook() and do the cleanup that way, but it's kind of broken that JNI_OnUnload() doesn't actually do what it is supposed to, and even more odd that the JNI documentation is completely silent as to why it doesn't actually work. I think I feel a bug report coming on ;-)
Posted by alanbur
( Feb 19 2006, 12:11:26 AM GMT )
Permalink
Comments [0]