调用JNI_CreateJavaVM会使程序崩溃

时间:2013-01-04 03:37:41

标签: java assembly jvm java-native-interface jrockit

我有一个C DLL,它使用JNI来代理对执行举重的底层java程序的任何调用。我正在动态加载jrockit jvm.dll以进行函数调用。

供应商A有一个C#DLL实际调用我的C DLL而另一个供应商B有一个C#程序调用供应商A的C#DLL。

使用供应商A的C#DLL测试时没有任何问题,但是在与供应商B的C#程序集成后,我通过JNI_CreateJavaVM初始化JVM的调用会使整个程序崩溃。

任何帮助都将不胜感激。

我收到的错误消息是:

[ERROR] Could not find allocated thread local data key in TIB
[ERROR] Could not create fast TLD
JRockit aborted: Unspecified Error(52)
Assertion failed: Could not create fast tld 
In vmDebug Before Abort() (src/jvm/runtime/debug/debug.c:103)

编辑1: 好吧我已经反汇编了jvm.dll并且它调用TlsAlloc后跟TLSSet并且到达显示错误消息的代码,cmp esi,edx在第二个图像中的je SHORT 04755D4B之前必须不相等。

第一张图像中的调用04755DD0的内容位于第二张图像中。

有没有人知道之前的计算(操纵esi和edx的1)是做什么的?

Disassembly 1 Disassembly 2

编辑2 :(回应P.T.) 我没有设置任何特定的线程系统,因此我认为它使用的是默认的线程系统,它是原生的,如下所示:http://docs.oracle.com/cd/E13222_01/wls/docs81b/jrockit/threads.html

您的猜测很可能是正确的,在查看反汇编时,我发现代码逻辑是这样的,它首先调用TlsAlloc,然后调用TlsSetValue将TlsAlloc返回的索引处的线程本地存储设置为常量幻数4711之后,它从线程信息块的开头使用eip循环寻找值4711,一旦找到它,代码再次调用TlsSetValue将值设置为1147,此时它检查eip是否为通过确保[eip]设置为1147来实际指向线程本地存储。

供应商B正在使用C#作为他们的程序,因此,他们将使用CLR虚拟机。一旦它到达供应商B调用我的DLL的点,他们就已经初始化了WPF棱镜和mef框架,将所有接口模块加载到它们各自的位置,初始化所有单例(在WPF prism术语中导出)模型并初始化MS工作流程。但是,当我将初始化代码转移到前几行时,jvm成功完成初始化(这不是初始化jvm的正确位置,我们还没有测试其余代码是否正常工作)。

当TlsSetValue失败时,代码只分支到错误,TlsSetValue是否有任何失败的原因?在供应商B的代码中我应该注意什么可能导致问题?

1 个答案:

答案 0 :(得分:3)

我遇到了同样的错误,我设法弄清楚发生了什么,至少在我的情况下。它看起来像JRockit中的一个错误,你的问题在调查它时非常有帮助。

对插槽中的“幻数”执行的搜索从TEB开始处开始延伸两页数据。但是,TEB本身内只有64个存储槽。请参阅http://msdn.microsoft.com/en-gb/library/windows/desktop/ms686708(v=vs.85).aspx

如果分配的存储槽的索引是64或更高,而不是将数据放入嵌入式阵列,Windows会将其放入TlsExpansionSlots指针指向的块中。由于这是在TEB之外,因此搜索幻数失败并且JRockit会产生此错误。

我的实例也发生在.NET程序中。我的猜测是CLR大量使用TLS,因此更有可能分配高插槽号。

在我的情况下,JRockit在尝试写日志行时实际上崩溃了,可能是因为它发生得太早以至于尚未创建日志。不确定您使用的是哪个版本的JRockit。我的是:

C:\>java -version
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
BEA JRockit(R) (build R27.6.5-32_o-121899-1.6.0_14-20091001-2107-windows-ia32, compiled mode)

我不知道这是否在以后的修订中得到修复。如果不是我们(即我的雇主)可能不得不用Oracle提出它。