我的dll代码从exe文件运行,但是无法从Java loadLibrary加载

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (28)

我创建了一个C ++模块来构建共享库文件,然后使用JNI从Java调用它。

我有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有一个暴露的方法,它从一些现有的库调用4个方法。如果我评论这4种方法,那么我的dll加载Java的罚款。我知道这是从我的DLL链接到一个库中的这些方法。Java看到依赖库有什么不同吗?我已经尝试加载依赖库首先,但我加载的DLL文件之一导致递归错误和堆栈溢出。

任何人都知道一个DLL导致递归错误堆栈溢出的方法?我需要它的方法,但我不能用java loadLibrary加载它。

这里是涉及的文件和实际的错误信息的更多细节。我在我的inital dll文件中添加了一个DllMain,以查看什么时候加载和何时加载。如果我编译相同的程序(my_plain_dll_to_call_JNI_DLL)作为exe文件,一切工作正常。如果我编译它并从我的Java程序加载它会发生。

  • myJavaProgram,只是调用System.loadLibrary()加载一个基本的.dll文件,该文件调用另一个包含JNI代码的dll中的方法。
  • my_plain_dll_to_call_JNI_DLL是我通过将它链接到我的dll库文件创建的一个dll,以测试依赖关系。它只是调用另一个dll调用我需要的本地代码的方法。
  • my_JNI_DLL.ll是一个与我需要从JNI访问的现有C ++编程库链接的dll文件。它包含直接调用现有源代码库中的方法。

我写了显示每行左边文本的文件名,以显示执行的内容。


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分配的内存和调试状态。

提问于
用户回答回答于

看起来像一个调用约定或类型大小与我不匹配。每个Windows C编译器都有自己的一套特性,并且Windows JNI头文件假定(最新版本)Microsoft Visual C ++。仔细观察警告 - 精确度的损失是不好的迹象。

例如,__int64是MSVC特定的。您需要找出Borland C中64位整数类型的名称,并将其映射到__int64包含之前jni.h

用户回答回答于

任何有用的hs_err ...日志文件。通常有一个堆栈回溯等指出一些东西。

还试图在调试器内运行java.exe(带有运行测试的参数)?

从上面的跟踪可以看到加载看起来工作正常(跟踪输出表明,dllentrypoint / dllmain已增加W /迹线输出)。

加载顺序如下:

  1. 依赖于负载的dll
  2. 加载DLL本身
  3. 调用dllentrypoint / dllmain w /进程附加

所以这已经超出了加载DLL的范围。

您是否检查过您是否使用Windows的调试/发布运行时?调试可能与发布冲突 - Java是释放,您的示例exe可能与您的dll构建相同。

扫码关注云+社区