我創建了一個C++模塊來構建共享庫文件,然後使用JNI從Java調用它。我的dll代碼從exe文件運行,但無法從Java加載loadLibrary
我有2個環境,Windows和Unix,我有一個C++可執行程序和一個Java程序,我只是爲每個環境重新編譯。
- 當我在Unix中編譯我的tester.exe程序並使用我的庫(.so)中的方法 運行它時,它工作正常。
- 當我在Unix中編譯我的Java程序並使用 Java的loadLibrary加載我的庫(.so)時,它工作正常。
當我在Windows中編譯我的tester.exe程序並使用我的庫(.dll)中的 方法運行它時,它工作正常。就像unix 版本一樣。
當我在Windows中編譯我的Java程序並使用Java的loadLibrary加載我的庫(.dll)時,它失敗。它表示嘗試訪問 無效地址。
我想不通,爲什麼在Windows上運行時也不會與Java調用LoadLibrary工作,但它的工作原理其他地方使用相同的代碼。如果我延遲加載我的庫使用的依賴DLL,那麼我的庫會在Java中加載,但不起作用。我知道有些特定的代碼會導致Java加載我的庫的問題,但我無法弄清楚爲什麼我的C++ EXE在相同的方法和庫中沒有問題。
我的DLL有1個暴露的方法,它從一些現有的庫調用4個方法。如果我評論這4種方法,那麼我的dll加載Java的罰款。我知道這是從我的DLL鏈接到一個庫中的這些方法。 Java看到依賴庫有什麼不同嗎?我已經嘗試加載依賴庫首先,但我加載的DLL文件之一導致遞歸錯誤和堆棧溢出。
任何人都知道一個DLL的方式,導致從遞歸錯誤堆棧溢出?我需要它的方法,但我不能用java loadLibrary加載它。
下面是有關涉及的文件和實際的錯誤消息的更多詳細信息。 我添加了一個DllMain到我的inital dll文件,以查看什麼時候加載。如果我編譯相同的程序(my_plain_dll_to_call_JNI_DLL)作爲exe文件,一切工作正常。如果我編譯它並從我的Java程序加載它會發生。
- myJavaProgram,只需調用System.loadLibrary()加載一個基本的.dll文件 調用在我的其他DLL的方法包含JNI代碼。
- my_plain_dll_to_call_JNI_DLL是我通過將它鏈接到我的 dll庫文件創建的一個dll,用於測試依賴關係。它只是從調用我需要的本機代碼的其他dll調用方法 。
- my_JNI_DLL.ll是一個dll文件,與我需要從JNI訪問的現有C++編程 庫鏈接。它包含對現有源代碼庫中的 方法的直接調用。
我寫的顯示文本每行左邊顯示的執行是在哪一層的文件名。
c:\java myJavaProgram
myJavaProgram: Java Static Method Entry.
myJavaProgram: Java Calling System.loadLibrary(my_plain_dll_to_call_JNI_DLL)
my_JNI_DLL.dll: Entering DllMain
my_JNI_DLL.dll: DLL_PROCESS_ATTACH
my_plain_dll_to_call_JNI_DLL: DLL_PROCESS_ATTACH
my_plain_dll_to_call_JNI_DLL: DLL_THREAD_ATTACH
my_plain_dll_to_call_JNI_DLL: DLL_THREAD_DETACH
my_plain_dll_to_call_JNI_DLL: DLL_PROCESS_DETACH
myJavaProgram: my_plain_dll_to_call_JNI_DLL Loaded!
myJavaProgram: Java Static Method Exit.
myJavaProgram: Entering Main().
my_plain_dll_to_call_JNI_DLL: In call_my_JNI_DLL_method
my_JNI_DLL.dll: In my_JNI_DLL_method
my_JNI_DLL.dll: Entering my_JNI_DLL_CheckEnvironmentVariables()
my_JNI_DLL.dll: Exiting my_JNI_DLL_CheckEnvironmentVariables
my_JNI_DLL.dll: Calling StartExistingNativeCode.
#
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (0xc0fb007e), pid=7500, tid=7552
#
# JRE version: 6.0_21-b06
# Java VM: Java HotSpot(TM) Client VM (17.0-b16 mixed mode, sharing windows-x86)
# Problematic frame:
# C [KERNELBASE.dll+0x9673]
#
# An error report file with more information is saved as:
# C:\hs_err_pid7500.log
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
my_plain_dll_to_call_JNI_DLL: DLL_PROCESS_DETACH
my_JNI_DLL.dll: Entering DllMain
my_JNI_DLL.dll DLL_PROCESS_DETACH
更新 我已經縮小的問題一個內存管理庫,從我的程序使用的另一個dll鏈接。它使用的dll是sh33w32.dll,它叫做SmartHeap,由我認爲是由一家名爲Microquil的公司提供。我有版本3.3,並且當Java LoadLibrary嘗試加載該dll時,它失敗。我不知道我能做些什麼來讓Java處理加載該庫。它必須與Java可以訪問的內存區域有關,而與Windows允許exe訪問的內存區域有關。這個exe文件對於SmartHeap庫沒有問題,但是Java不允許我使用它。任何想法或經驗處理這個?我試圖通過重新編譯其他庫來移除鏈接的庫,但隨後代碼中的正常調用失敗,通常無法正常工作。
附加資料找到 即在失敗在Java加載DLL被稱爲MemRegisterTask功能。它來自Microquill的名爲SmartHeap的產品。這裏是我找到關於這個功能的文檔。我認爲這種內存分配是導致java無法加載它的原因。
MemRegisterTask初始化SmartHeap庫。在大多數平臺上,您不需要調用MemRegisterTask,因爲SmartHeap會在您進行第一次調用時自行初始化。
SmartHeap爲每個任務或進程維護註冊引用計數。每次調用MemRegisterTask時,該引用計數都會增加。如果您最後一次調用SmartHeap發生在應用程序準備終止之前,您可以調用MemUnregisterTask來終止SmartHeap。 MemUnregisterTask將註冊引用計數遞減1 - 當計數爲零時,SmartHeap將釋放與當前任務或進程關聯的任何SmartHeap分配的內存和調試狀態。
也許發佈一些代碼會幫助人們看到更多。只是一個快速檢查:你是正確地暴露你的DLL到Java(例如:http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniexamp.html#impl) – JScoobyCed 2012-04-06 15:11:22
我不知道我可以發佈代碼,因爲工作規則。我已經解決了我遇到的所有其他JNI錯誤,所以我試圖瞭解這些概念,以瞭解是否可以看到它失敗的原因。我暴露了我的java程序正確使用的1方法。問題是DLL甚至不能在Windows Java中加載,Unix Java可以正常工作。 – Logan 2012-04-06 15:30:59
從異常消息看來,C++函數的參數不正確(編組爲不同於預期的類型),或者鏈接不正確。有可能C++庫是用不同於JNI提供/假定的調用約定編譯的。 – Attila 2012-04-06 18:08:02