web-dev-qa-db-ja.com

java.lang.UnsatisfiedLinkError:ネイティブライブラリXXX.soはすでに別のクラスローダーにロードされています

次のコードを含む1つのWebアプリケーションをデプロイしました。

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

ここで、同じコードを持つ別のWebアプリケーションをデプロイしました。ライブラリをロードしようとすると、次のエラーがスローされます。

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

これら両方のアプリケーションを同時に実行したいです。

今まで私が試したこと:

  1. あるアプリケーションにライブラリをロードし、上記の例外を別のアプリケーションにキャッチしました
  2. 両方のアプリケーションからjarを削除し、opencv.jarをTomcatのクラスパス(つまり、/ usr/share/Tomcat7/lib)に配置しました。

しかし、上記のどれもうまくいかず、これを行うための提案はありますか?

編集:オプション2の場合、

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
    at org.opencv.highgui.Highgui.imread_1(Native Method)
    at org.opencv.highgui.Highgui.imread(Highgui.Java:362)
15
Bhushan

問題は、OpenCVがネイティブライブラリの初期化を処理する方法にあります。

通常、ネイティブライブラリを使用するクラスには、ライブラリをロードする静的初期化子があります。この方法により、クラスとネイティブライブラリは常に同じクラスローダーにロードされます。 OpenCVを使用すると、アプリケーションコードはネイティブライブラリをロードします。

現在、ネイティブライブラリは1つのクラスローダーにしかロードできないという制限があります。 Webアプリケーションは独自のクラスローダーを使用するため、あるWebアプリケーションがネイティブライブラリをロードした場合、別のWebアプリケーションはこれを実行できません。したがって、ネイティブライブラリをロードするコードはwebappディレクトリに配置できませんが、コンテナの(Tomcat)共有ディレクトリに配置する必要があります。上記の通常のパターン(クラスを使用する静的イニシャライザのloadLibrary)で記述されたクラスがある場合、クラスを含むjarを共有ディレクトリに配置するだけで十分です。ただし、OpenCVとloadLibraryをWebアプリケーションコードで呼び出すと、ネイティブライブラリが「間違った」クラスローダーにロードされたままになり、UnsatisfiedLinkErrorが取得されます。

「正しい」クラスローダーにネイティブライブラリをロードさせるには、loadLibraryのみを実行する単一の静的メソッドで小さなクラスを作成できます。このクラスを追加のjarに配置し、このjarを共有Tomcatディレクトリに配置します。次に、Webアプリケーションで、System.loadLibraryの呼び出しを新しい静的メソッドの呼び出しに置き換えます。これにより、OpenCVクラスとそのネイティブライブラリのクラスローダーが一致し、ネイティブメソッドを初期化できます。

編集:コメント者の要求に応じた例

の代わりに

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

使用する

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

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

Tomcatバージョン_9.0.13_、_8.5.35_、および_7.0.92_の時点で、この問題に対処するために次のオプションを追加しました BZ-628

1) JniLifecycleListener を使用してネイティブライブラリをロードします。

例えば_opencv_Java343_ライブラリをロードするには、次を使用できます。

_<Listener className="org.Apache.catalina.core.JniLifecycleListener"
          libraryName="opencv_Java343" />
_

2)Systemの代わりに load() または loadLibrary() from _org.Apache.Tomcat.jni.Library_ を使用します。

例えば.

_org.Apache.Tomcat.jni.Library.loadLibrary("opencv_Java343");
_

これらのオプションのいずれかを使用すると、Common ClassLoaderを使用してネイティブライブラリがロードされるため、すべてのWebアプリで使用できます。

0
isapir