java.lang.UnsatisfiedLinkError: Native Library XXX.so 已经加载到另一个类加载器中 [英] java.lang.UnsatisfiedLinkError: Native Library XXX.so already loaded in another classloader

查看:20
本文介绍了java.lang.UnsatisfiedLinkError: Native Library XXX.so 已经加载到另一个类加载器中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经部署了一个 Web 应用程序,其中包含以下代码.

System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);

现在,我部署了另一个具有相同代码的 Web 应用程序.当它尝试加载库时,它抛出以下错误.

线程Thread-143"中的异常java.lang.UnsatisfiedLinkError:本机库/usr/lib/jni/libopencv_java248.so 已加载另一个类加载器

我想同时运行这两个应用程序.

到目前为止我已经尝试过:

  1. 在一个应用程序中加载库并在另一个应用程序中捕获上述异常
  2. 从两个应用程序中删除 jars 并将 opencv.jar 放入 Tomcat 的类路径(即在/usr/share/tomcat7/lib 中).

但以上都没有奏效,有什么建议可以让我做到这一点吗?

对于选项二,

System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

此行有效,但在我实际要使用该库时出现异常.那是当我做以下

Mat mat = Highgui.imread("/tmp/abc.png");

我得到这个异常

java.lang.UnsatisfiedLinkError: org.opencv.highgui.Highgui.imread_1(Ljava/lang/String;)J在 org.opencv.highgui.Highgui.imread_1(本机方法)在 org.opencv.highgui.Highgui.imread(Highgui.java:362)

解决方案

问题在于 OpenCV 如何处理原生库的初始化.

通常使用本机库的类会有一个静态初始化器来加载库.这样,类和本机库将始终在同一个类加载器中加载.使用 OpenCV,应用程序代码加载本机库.

现在有一个限制,即一个本地库只能在一个类加载器中加载.Web 应用程序使用它们自己的类加载器,因此如果一个 Web 应用程序加载了本机库,另一个 Web 应用程序就不能这样做.因此加载本机库的代码不能放在 webapp 目录中,而必须放在容器的(Tomcat)共享目录中.当你有一个用上面通常的模式编写的类(loadLibrary 在 using class 的静态初始化程序中)时,将包含该类的 jar 放在共享目录中就足够了.然而,使用 OpenCV 和 Web 应用程序代码中的 loadLibrary 调用,本机库仍将在错误"的类加载器中加载,您将得到 UnsatisfiedLinkError.>

要使正确"的类加载器加载本机库,您可以创建一个小类,其中包含一个仅执行 loadLibrary 的静态方法.将这个类放在一个额外的jar 中,并将这个jar 放在共享的Tomcat 目录中.然后在 Web 应用程序中,用对新静态方法的调用替换对 System.loadLibrary 的调用.这样,OpenCV 类的类加载器和它们的本地库就会匹配,并且可以初始化本地方法.

评论者要求的示例

代替

公共类 WebApplicationClass {静止的 {System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);}}

使用

公共类 ToolClassInSeparateJarInSharedDirectory {public static void loadNativeLibrary() {System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);}}公共类 WebApplicationClass {静止的 {ToolClassInSeparateJarInSharedDirectory.loadNativeLibrary();}}

I have deployed one web-application, which contains following code.

System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);

Now, I deployed another web-application which also have same code. When it tries to load library, it throwing following error.

Exception in thread "Thread-143" java.lang.UnsatisfiedLinkError: 
Native Library /usr/lib/jni/libopencv_java248.so already loaded in
another classloader

I want to run these both application simultaneously.

Till now what I have tried:

  1. Loaded library in one application and caught above exception into another application
  2. Removed jars from both application and put opencv.jar into Tomcat's classpath(ie in /usr/share/tomcat7/lib).

But none of above worked, any suggestions by which I can do this ?

Edit: for option two,

System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

This line works but gets exception when I am actually going to use that library. That is when I do following

Mat mat = Highgui.imread("/tmp/abc.png");

And I get this exception

java.lang.UnsatisfiedLinkError: org.opencv.highgui.Highgui.imread_1(Ljava/lang/String;)J
    at org.opencv.highgui.Highgui.imread_1(Native Method)
    at org.opencv.highgui.Highgui.imread(Highgui.java:362)

解决方案

The problem is with how OpenCV handles the initialization of the native library.

Usually a class that uses a native library will have a static initializer that loads the library. This way the class and the native library will always be loaded in the same class loader. With OpenCV the application code loads the native library.

Now there's the restriction that a native library can only be loaded in one class loader. Web applications use their own class loader so if one web application has loaded a native library, another web application cannot do the same. Therefore code loading native libraries cannot be put in a webapp directory but must be put in the container's (Tomcat) shared directory. When you have a class written with the usual pattern above (loadLibrary in static initializer of using class) it's enough to put the jar containing the class in the shared directory. With OpenCV and the loadLibrary call in the web application code however, the native library will still be loaded in the "wrong" class loader and you will get the UnsatisfiedLinkError.

To make the "right" class loader load the native library you could create a tiny class with a single static method doing only the loadLibrary. Put this class in an extra jar and put this jar in the shared Tomcat directory. Then in the web applications replace the call to System.loadLibrary with a call to your new static method. This way the class loaders for the OpenCV classes and their native library will match and the native methods can be initialized.

Edit: example as requested by a commenter

instead of

public class WebApplicationClass {
    static {
        System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
    }
}

use

public class ToolClassInSeparateJarInSharedDirectory {
    public static void loadNativeLibrary() {
        System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
    }
}

public class WebApplicationClass {
    static {
        ToolClassInSeparateJarInSharedDirectory.loadNativeLibrary();
    }
}

这篇关于java.lang.UnsatisfiedLinkError: Native Library XXX.so 已经加载到另一个类加载器中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆