Wednesday, September 14, 2011

java.lang.UnsatisfiedLinkError: Native Library HelloWorld.dll already loaded in another classloader

Problem:

There's no way to unload a dll loaded by a classloader. DLL will be unloaded only during classloader garbage collection.
Also a dll cannot be loaded more than once in a jvm even if we use distinct classloaders.

This is a known issue in JDK and more information can be found in the links below.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4225434
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5075039

Update from bugs.sun.com

A native library can not be loaded into two live ClassLoaders objects
at the same time and the reasoning for this is obvious -- native code
that caches JNI IDs will get wrong answers.  The long term fix for
this is a way for the native library to tell the VM (on JNI_OnLoad)
that it is multiple-ClassLoader safe.  That would be an RFE.

However when the ClassLoader has died, the ClassLoader.NativeLibrary
finalizer could unload the library.  Currently we do not do this
and this is intentional -- unloading libraries is an MT unsafe
operation on NT and there are troubles with runFinalizersOnExit.
A workaround would be to have the class that loads a native library
be loaded by a shared classloader (through the parenting mechanism of
ClassLoaders in 1.2).

Sample code to reproduce the problem:

1) Created a class HelloWorld.java that declares a native method.
2) Generated the C header file, wrote the C implementation and created a DLL file. All these steps are clearly explained in the following link.
http://java.sun.com/docs/books/jni/html/start.html
3) To reproduce the problem, i wrote a simple java class which loads the DLL file and calls the native method multiple (three) times.
Each time it tries to load the native library and calls the native method in a different classloader.
The code snippet is shown in the image below.
Complete codesnippets and workarounds to overcome the problem will be provided in the next post.

No comments: