1. 程式人生 > >java.lang.UnsatisfiedLinkError解決方法彙集(轉載)

java.lang.UnsatisfiedLinkError解決方法彙集(轉載)

執行JSP報表程式頁面出現java.lang.UnsatisfiedLinkError: CC錯誤有以下幾種原因和處理方法:

1、請檢視控制檯的錯誤資訊
a:如果控制檯的訊息是類似

java.lang.UnsatisfiedLinkError: no MRChkLib in java.library.path,Error loading library MRChkLib

這樣的錯誤資訊,那麼是因為MRChkLib.dll沒有拷貝到windows的System32目錄下. (MRChkLib.dll是加密鎖的JAVA介面檔案,檔案在報表安裝目錄DogDriver/JavaAPI下可以找到) 並且要注意PATH環境變數中要包含System32目錄。(如果伺服器作業系統是Linux,那麼使用報表安裝目錄DogDriver/JavaAPI 下的libMRChkLib.so檔案,將libMRChkLib.so複製到WebServer的啟動bin目錄。如果在這個目錄下仍然出現can not load library錯誤,請設定系統環境變數LD_LIBRARY_PATH的值為libMRChkLib.so所在的目錄。
例如:如果libMRChkLib.so在/somedir目錄下,則 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/somedir)

b:如果控制檯的訊息是類似

java.lang.unsatisfiedLinkError :native libery c:/winnt/system32/mrchklib.dll already loaded in another classLoader error loading mrchklib.dll

這樣的錯誤資訊,那麼是因為WebAPP在重新被啟動之後,無法再次載入動態庫造成的,這是java的約束,Java不允許一個例項載入多次動態 庫.可以這樣解決,將mr.jar拷貝到WebServer的lib目錄,刪除/WEB-INF/lib目錄下的mr.jar,然後重新啟動 webserver。


2、如果一個webserver上有多個報表應用,請將/WEB-INF/lib/mr.jar移動到WebServer的lib目錄下,確保每一個Web應用程式目錄下都沒有mr.jar,而只有WebServer的lib目錄下有該檔案,重啟webserver.


3、一個Webserver上只能有一個mr.jar檔案,刪掉多餘的mr*.jar檔案,然後清除webserver臨時檔案,重新啟動webserver。 =================================================================================== 最近專案中用到了jni,於是安裝了eclipse的cdt和MinGW來用,以前沒怎麼動過C語言,網上找了下教程,倒是挺容易的,一路弄下來也沒提示什麼錯誤,但是在最後呼叫本地方法時卻遇到了大麻煩,總是提示找不到方法。即使一個簡單的HelloWorld,也是一樣
Exception in thread "main" java.lang.UnsatisfiedLinkError: HelloWorld.print()V
奇怪了,loadLibrary()沒有問題,怎麼會找不到方法呢?用dll export viewer察看,匯出的方法為
函式名 地址 偏移量
[email protected]
0x67741250 0x00001250

實在沒辦法了,只好安裝龐大的visual studio重新來編譯,呼叫成功了!
再次用dll export viewer檢視,發現函式名的前面多了一條下劃線
函式名 地址 偏移量
[email protected] 0x67741250 0x00001250
看來是給MinGW少傳了某個引數,經過網上查閱資料,終於找到一個解決方案:給MinGW的ld命令指定一個引數--kill-at即可
gcc -Wl, --kill-at -shared -o jnihello.dll HelloWorld.c
再次用dll export viewer檢視,發現匯出的函式名稱變為
函式名 地址 偏移量
Java_HelloWorld_print 0x67741250 0x00001250

--kill-at指令去掉了函式名稱字尾的@,並沒有像msvc那樣新增字首的下劃線 ======================================================================== 現象: java.lang.UnsatisfiedLinkError: Native Library xxx.dll already loaded in another classloader at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1551) at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1511) at java.lang.Runtime.loadLibrary0(Runtime.java:788) at java.lang.System.loadLibrary(System.java:834) 分析: 這種錯誤在我們使用熱啟動方式釋出某個使用了JNI技術的Web應用時,並將呼叫年native方法的jar包獨立部署在該應用下面,當我們的Web應用 有了更新以後,在呼叫到該jar包封裝的native方法時,會丟擲該錯誤。(以上OS為Windows,若是Linux或Unix,應該是xxx.so 報錯) 這是因為Web伺服器已經在第一次載入該應用時,已經load了該dll,當該應用被再次熱啟動時,該dll將重新被載入,於是報錯。 解決方案: 一、將含有JNI呼叫的jar包部署在Web伺服器的公用lib庫中。Web應用再發布時可以不用載入; 二、jar包部署不變,在該Web中實現一個listener,監聽是否第一次啟動,若不是第一次啟動,遮蔽掉該jar包所含dll的載入。 ========================================================================
類裝入問題:UnsatisfiedLinkError

在把本機呼叫連結到對應的本機定義時,類裝入器扮演著重要角色。如果程式試圖裝入一個不存在或者放錯的本機庫時,在連結階段的解析過程會發生 UnsatisfiedLinkError。JVM 規範指定 UnsatisfiedLinkError 是:

對於宣告為 native 的方法,如果 Java 虛擬機器找不到和它對應的本機語言定義,就會丟擲該異常。

當呼叫本機方法時,類裝入器會嘗試裝入定義了該方法的本機庫。如果找不到這個庫,就會丟擲這個錯誤。

清單 6 演示了丟擲 UnsatisfiedLinkError 的測試用例 :



清單 6. UnsatisfiedLinkError.java
                        public class UnsatisfiedLinkErrorTest {
public native void call_A_Native_Method();
static {
System.loadLibrary("myNativeLibrary");
}
public static void main(String[] args) {
new UnsatisfiedLinkErrorTest().call_A_Native_Method();
}
}

這段程式碼呼叫本機方法 call_A_Native_Method(),該方法是在本機庫 myNativeLibrary 中定義的。因為這個庫不存在,所以在程式執行時會發生以下錯誤:

The java class could not be loaded. java.lang.UnsatisfiedLinkError:
Cant find library myNativeLibrary (myNativeLibrary.dll)
in sun.boot.library.path or java.library.path
sun.boot.library.path=D:/sdk/jre/bin
java.library.path= D:/sdk/jre/bin
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2147)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:2006)
at java.lang.Runtime.loadLibrary0(Runtime.java:824)
at java.lang.System.loadLibrary(System.java:908)
at UnsatisfiedLinkErrorTest.<clinit>(UnsatisfiedLinkErrorTest.java:6)

本機庫的裝入由呼叫 System.loadLibrary() 方法的類的類裝入器啟動 —— 在清單 6 中,就是 UnsatisfiedLinkErrorTest 的類裝入器。根據使用的類裝入器,會搜尋不同的位置:

  • 對於由 bootstrap 類裝入器裝入的類,搜尋 sun.boot.library.path
  • 對於由擴充套件類裝入器裝入的類,先搜尋 java.ext.dirs,然後是 sun.boot.library.path,然後是 java.library.path
  • 對於由系統類裝入器裝入的類,搜尋 sun.boot.library.path,然後是 java.library.path

在清單 6 中,UnsatisfiedLinkErrorTest 類是由系統類裝入器裝入的。要裝入所引用的本機庫,這個類裝入器先查詢 sun.boot.library.path,然後查詢 java.library.path。因為在兩個位置中都沒有需要的庫,所以類裝入器丟擲 UnsatisfiedLinkageError

==========================================================================

java.lang.UnsatisfiedLinkError 出現這種錯誤的原因是一般是java虛擬機器找不到宣告為native方法的本地語言定義時,出現的錯誤。在我的理解過程中我一般都認為是由於匯入dll或 者匯入lib檔案不正確導致的。有些需要靜態匯入就沒有問題(即在前面加static來匯入lib檔案),如果是不加static匯入也就是動態匯入的時 候,那麼需要新增catch的丟擲異常來解決,如

try{
    System.loadLibrary("vtkCommonJava");
    System.loadLibrary("vtkFilteringJava");
    System.loadLibrary("vtkIOJava");
    System.loadLibrary("vtkImagingJava");
    System.loadLibrary("vtkGraphicsJava");
    System.loadLibrary("vtkRenderingJava");
   }catch(Throwable e)
   {
    System.out.println("The load problem");
   }

這種方式來判斷,或者直接在類前面新增

static{

   System.loadLibrary("vtkCommonJava");
    System.loadLibrary("vtkFilteringJava");
    System.loadLibrary("vtkIOJava");
    System.loadLibrary("vtkImagingJava");
    System.loadLibrary("vtkGraphicsJava");
    System.loadLibrary("vtkRenderingJava");

} ================================================================================
關於java.lang.UnsatisfiedLinkError(JNI)
    目標:把pbp1.0的java包和native移到GEM中,並使GEM在新的虛擬機器上正常執行
    背景:GEM(1)有一堆java包和native函式,pbp1.0是虛擬機器和JAVA基本包,要將pbp1.0的虛擬機器移走只用它的JAVA基本包和native函式。
    問題:在將GEM和pbp1.0的native函式生成一個動態庫後在程式裡System.loadLibrary()無法載入,報java.lang.UnsatisfiedLinkError
    解決過程:
    1,理論
    我們知道,JAVA呼叫native函式時,必須通過System.loadLibrary()或System.load將其native函式所在動態庫 載入到虛擬機器。並在執行時指明-Djava.library.path或-Dsun.boot.library.path,將其指向包含有native函 數的動態庫所在位置。
    2,實施
    我按這個步驟操作完成後就是無法載入我生成的動態庫libgem.so,這個庫用到的其他動態庫包括:rt,pthread,freetype,dl, directfb,而directfb用到的動態庫有rt,dl,pthread,freetype,jpeg,png,這些庫除了directfb要生 成外其餘都在/lib目錄下存在。
    3,思路
    先寫了一個Hello的測試用例。發現在native裡所使用到其他動態庫時,無論是否存在於相關目錄,仍然無法載入。然後經過修改編譯選項,把所使用到的動態庫連動態連線進目標庫,如下:
    $(GCC) -fPIC -shared -o libdirectfb.so ... -lpng -ljpeg -lpthread -lrt -ldl, -lfreetype
    經過這麼一個修改後,directfb可以載入。
    這也說明System.loadLibrary()所載入的動態庫所引用的所有符號都要能找到。如果有一個無法找到將無法載入。可以寫一個空的main ()函式,對你的動態庫進行連線,如果動態庫裡所引用的符號在指定的動態庫和本身找到不到則無法編譯通過,那麼這個動態庫也肯定載入不了。
    4,問題解決
    按照這個思路,對libgem.so的編譯Makefile做相應修改後,問題解決!並在LD_LIBRARY_PATH加入動態庫所在目錄。

(1) MHP (Multimedia Home Platform) was developed by the DVB Project as the world's first open standard for interactive television. It is a Java-based environment which defines a generic interface between interactive digital applications and the terminals on which those applications execute. MHP was designed to run on DVB platforms but there was a demand to extend the interoperability it offers to other digital television platforms. This demand gave rise to GEM, or Globally Executable MHP, a framework which allows other organisations to define specifications based on MHP.

====================================================================================

另外,還可能是dll本身的問題,使用release版的,而不要用debug版的