我的 dll 代码从 exe 文件工作,但无法从 Java 加载库加载
我创建了一个C++模块来构建到共享库文件中,然后使用JNI从Java调用它。
我有2个环境,Windows和Unix,我有一个C++可执行程序和一个Java程序,我只是为每个环境重新编译。
- 当我在Unix中编译我的测试器.exe程序并使用我的库(.so)中的方法运行它时,它工作正常。
- 当我在Unix中编译我的Java程序并使用Java的loadLibrary加载我的库(.so)时,它工作正常。
当我在Windows中编译测试器.exe程序并使用我的库中的方法(.dll)运行它时,它工作正常。就像unix版本一样。
当我在Windows中编译我的Java程序并使用Java的loadLibrary加载我的库(.dll)时,它失败了。它显示尝试访问无效地址。
我无法弄清楚为什么它在Windows中运行时不能与Java加载库一起使用,但它可以使用相同的代码在其他任何地方工作。如果我延迟加载我的库使用的依赖 DLL,则我的库在 Java 中加载,但不起作用。我知道有特定的代码会导致Java加载我的库的问题,但我无法弄清楚为什么我的C++exe在相同的方法和库上没有问题。
我的dll有1个公开的方法,它从一些现有库中调用4个方法。如果我注释掉这4种方法,那么我的dll在Java中加载得很好。我知道这与我的dll链接到的库中的这些方法有关。Java如何看待依赖库有什么不同吗?我尝试先加载依赖库,但我加载的其中一个dll文件导致递归错误和堆栈溢出。
有人知道一种解决导致递归错误导致堆栈溢出的DLL的方法吗?我需要其中的方法,但我无法使用java加载库加载它。
以下是有关所涉及的文件和实际错误消息的更多详细信息。我在最初的dll文件中添加了一个DllMain,只是为了看看加载了什么以及何时加载。如果我将相同的程序(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调用一个方法,该dll正在调用我需要的本机代码。
- my_JNI_DLL.ll是一个dll文件,链接到现有的C++编程库,我需要从JNI访问。它包含对现有源代码库中方法的直接调用。
我写了文件名,在每行的左侧显示文本,以显示执行所在的层。
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不允许我使用它。任何想法或经验来处理这个问题?我尝试通过重新编译其他库来删除链接的库,但随后代码中的正常调用失败,正常工作。
找到的其他信息dll 中无法在 java 中加载的函数称为 MemRegisterTask。它来自Microquill的一款名为SmartHeap的产品。以下是我找到的有关此函数的文档。我认为这种内存分配是导致java无法加载它的原因。
MemRegisterTask 初始化 SmartHeap Library。在大多数平台上,您不需要调用MemRegisterTask,因为SmartHeap会在您进行第一次调用时初始化自身。
SmartHeap 为每个任务或进程维护一个注册引用计数。每次调用 MemRegisterTask 时,此引用计数都会递增。如果最后一次调用 SmartHeap 发生在应用程序准备终止之前,则可以调用 MemUnregisterTask 来终止 SmartHeap。MemUnregisterTask 将注册引用计数递减 1 — 当计数为零时,SmartHeap 将释放与当前任务或进程关联的任何 SmartHeap 分配的内存和调试状态。