Solve the problem of “java.lang.UnsatisfiedLinkError: Native Library .dll already loaded in another classloader”

The author encountered such a situation some time ago, that is, the same applet was used in two projects, and then the dll operation (using jni or jna) was called in the applet, and then the call was made on the client. The actual access process is as follows:
first visit an interface of project A, call appletA in the interface, and then directly visit the interface of project B without closing the browser, call appletB in the interface. AppletA and appletB are actually the same applet, but this applet is used in two projects, and both projects are directly accessed. At this time, when accessing appletB, an error will appear:

xxx NOT loaded java.lang.UnsatisfiedLinkError: Native Library XXX.dll already loaded in another classloader

If the access is from appletB to appletA, the same error will occur when accessing appletA.
Because, in a tab page, multiple applets are actually running on the same jvm, but different classLoaders are used when loading applets. Therefore, whether appletA runs first or appletB runs first, the final situation is that the dependent dll will be loaded by the same jvm, and the above error will occur.

After google, I found that many developers have encountered the same problem. Some are because two projects that need to access the same jni call are deployed in the same javaEE container (weblogic, jboss), and some are like the author. The same experience. The final conclusion is that, in a jvm, it is not allowed to load a dll twice. Therefore, when the subsequent jni calls, try to load the same dll again, and the above error will be reported at this time. Because of this error, the corresponding java class must not be initialized, so the corresponding project or applet must not start.

Solving this problem is actually very simple. Extract the code that accesses the jni separately, instead of directly letting the project’s own classLoader load it, just let it be loaded by the systemLoader. One way is to encapsulate this part of the code separately into a jar, and place it in a place where the java systemLoader can load, such as the lib/ext directory. Then, this code is still called in the project. Since the code to access the dll is loaded by the systemLoader, when multiple projects access the same dll at the same time, it can be avoided to load it again. Because, when the second project is accessed, the class found has already been loaded by the systemLoader, so the classLoader of the project itself will not load this class anymore.

In contrast, the original appletA and appletB have been modified to have this structure: appletA, appletB, and jniAccess.jar, where jniAccess.jar is placed in the ext directory of the lib directory of jre. In this way, there is no problem when you access the applet again.

 

Similar Posts: