legacy-knowledge-base
公開されました Sep. 10, 2025

java.lang.UnsatisfiedLinkError:ネイティブライブラリxxxxは、再デプロイ後に別のクラスローダーで既にロードされています。

written-by

Jorge Diaz

How To articles are not official guidelines or officially supported documentation. They are community-contributed content and may not always reflect the latest updates to Liferay DXP. We welcome your feedback to improve How To articles!

While we make every effort to ensure this Knowledge Base is accurate, it may not always reflect the most recent updates or official guidelines.We appreciate your understanding and encourage you to reach out with any feedback or concerns.

legacy-article

learn-legacy-article-disclaimer-text

問題

私たちのカスタム開発では、 JNIを使用してロードされた外部ネイティブを使用する Jar ライブラリを使用しています。

カスタム開発したものをクリーンな環境にデプロイすると、すべて正常に動作しますが、再デプロイすると、以下のエラーが発生します:

java.lang.UnsatisfiedLinkError: Native Library xxxx already loaded in another classloader
at java.base/java.lang.ClassLoader$NativeLibrary.loadLibrary(ClassLoader.java:2456)
at java.base/java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2684)
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2649)

アプリケーションサーバーを再起動すると、次の開発の再デプロイまで問題が解決されます。

Environment

  • Liferay DXP 7.0-7.4

解決策

このエラーは、モジュールの停止と再起動時のOSGIフレームワークの動作に起因しています。 このような場合、OSGIが行うのは、モジュールのすべてのクラスを再ロードする新しいクラスローダを作成することです:

  • 停止する前にモジュールによって使用されたものに対応するもの。
  • と、再度起動した後のモジュールに対応するものを選択します。

古いクラスローダーは、それによってロードされたクラスへのメモリ参照がなくなり、ガベージコレクションが実行されると、メモリから完全に取り除かれます。

これは、ライブラリがOSGIに対応していない場合、例えば、静的変数を持っていたり、ネイティブのオペレーティングシステムライブラリを使用している場合、問題を引き起こす可能性があります。 このような場合、正しく解放されない参照が存在する可能性があります。

一方、ネイティブ・ライブラリの場合、JVMが課す制限として、異なるクラスローダーによって複数回ロードすることはできません。 https://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html#library_versionを参照してください。

JDKでは、クラスローダーごとにネイティブライブラリのセットを管理しています。 同じJNIネイティブライブラリを複数のクラスローダーにロードすることはできません。 そうすると、 UnsatisfiedLinkError がスローされます。 例えば、 System.loadLibrary は、 UnsatisfiedLinkError をスローし、2つのクラスローダーにネイティブライブラリをロードするために使用します


したがって、このようなJNIによるネイティブライブラリのロードを利用するJARの場合、ライブラリを含むモジュールを個別に再起動しても、OSGIによるJARのロードにエラーが発生することはないでしょう。 また、複数のOSGIモジュールが同じライブラリをロードしようとすることもできないでしょう。

module.framework.system.packages.extra プロパティを使用した回避方法。


JARライブラリをOSGIフレームワーク全体にグローバルにロードする回避策があり、それはJARをLiferay librariesフォルダに追加し、このJARのパッケージをそれを利用するモジュールに公開するようにOSGIフレームワークを設定することからなります。

この回避策は、他に方法がない場合にのみ使用し、ライブラリがLiferayが標準装備しているJavaクラスのパッケージと衝突しない限りは使用する必要があります。

ライブラリをグローバルにロードするためには、Liferayサーバーを停止した状態で、以下の手順を踏む必要があります:

  1. 問題のあるJARをフォルダにコピーしてください:
    • DXP 7.0-7.3です: [LIFERAY_HOME]/tomcat-9.x.x/webapps/ROOT/WEB-INF/lib
    • DXP 7.4です: [LIFERAY_HOME]/tomcat-9.x.x/webapps/ROOT/WEB-INF/shielded-container-lib
  2. portal-impl.jar ファイルに行き、そこから portal.properties fファイルを取得し、そこから module.framework.system.packages.extra section をコピーする必要があります。 https://github.com/liferay/liferay-portal/blob/7.4.3.24-ga24/portal-impl/src/portal.properties#L7349-L7381 (注意:このスニペットは新しい Liferay DXP 製品のアップデートごとに変更することがあるので、アップデートごとに確認する必要がある)
  3. module.framework.system.packages.extra セクションを portal-ext.propertiesファイルにコピーします。
  4. lib / shielded-container-libにコピーしたライブラリパッケージをカンマで区切ってセクションの最後に追加します。


このアプローチにより、ライブラリのクラスは、それを必要とするすべてのOSGIモジュールで利用可能になります。

詳しくは、以下の記事をご覧ください: Resolving ClassNotFoundException and NoClassDefFoundError in OSGi Bundles - The Missing Class Belongs to a Global Library

最後に、問題のJARを使用するOSGIモジュールで、当該パッケージとの依存関係を宣言する必要があることを示してください(コンパイル時にのみ依存する「コンパイルオンリー」タイプ)もしモジュールが当該依存関係を宣言しないなら、当該クラスへのアクセスはできません。

追加情報

did-this-article-resolve-your-issue

legacy-knowledge-base