Java 如何检查JVM执行堆栈以确定堆栈损坏的原因

Java 如何检查JVM执行堆栈以确定堆栈损坏的原因,java,windows,jvm,java-native-interface,Java,Windows,Jvm,Java Native Interface,我有一个JUnit测试,大致如下所示: double doubleValue = 100.0 + 1E-14; long longValue = nativeInvokeWrapper(doubleValue, ...); assertEquals(doubleValue, Double.longBitsToDouble(longValue)); 背景 函数nativeInvokeWrapper调用另一个Java函数,该函数反过来调用JNI函数,JNI函数最终调用\uu stdcall“C”函

我有一个JUnit测试,大致如下所示:

double doubleValue = 100.0 + 1E-14;
long longValue = nativeInvokeWrapper(doubleValue, ...);
assertEquals(doubleValue, Double.longBitsToDouble(longValue));
背景 函数
nativeInvokeWrapper
调用另一个Java函数,该函数反过来调用JNI函数,JNI函数最终调用
\uu stdcall
“C”函数,并将
doubleValue
作为参数传递。“C”函数返回一个64位的值,该值按位等于它接收到的双参数,并且该返回值将被传播出去,直到它被
nativeInvokeWrapper
返回

关键是
nativeInvokeWrapper
的预期返回值是一个
long
,按位等于
doubleValue

问题
  • 当我单独运行JUnit测试时,它通过了
  • 当我运行整个JUnit测试套件时,所有其他测试都通过了,但这个测试失败了
  • 当我在上面的测试中设置了一个断点来运行整个JUnit测试套件并逐步完成它时,它工作得很好
我的本机函数可能会以某种微妙的方式破坏JVM状态。。。有趣的是,如果我读取变量
longValue
的值两次,问题似乎就消失了。例如,如果我将测试代码更改为:

double doubleValue = 100.0 + 1E-14;
long longValue = nativeInvokeWrapper(doubleValue, ...);
long longValue2 = longValue;
double doubleValue2 = Double.longBitsToDouble(longValue2);
if (doubleValue != doubleValue2)
{
    String msg = "d=" + doubleValue + ", d2=" + doubleValue2 + "\n" +
                 "l=" + longValue + ", l2=" + longValue2;
    throw new RuntimeException(msg);
}
然后运行整个JUnit测试套件,它抛出:

java.lang.RuntimeException: d=100.00000000000001, d2=NaN
l=4636737291354636289, l2=
  4636737291354636289
请注意,两个
double
值不同,但
long
值相同

当我在调试器中单步执行时,一切正常。这就好像通过在需要将
longValue
传递给
Double.longBitsToDouble()
方法之前强制“读取”它,状态损坏问题就消失了

救命啊! 我想要的是关于如何调试/确定根本原因的想法。如上所述,在常规Eclipse调试器中单步执行是没有用的,因为读取
longValue
似乎可以解决问题

我还能看什么?我还可以使用哪些其他工具来查看Java线程执行堆栈的内部状态,以查看是否有内容已损坏


更新:如果我关闭JIT(使用
-Xint
运行JVM),一切都会正常工作。因此,这与JIT编译代码特定的一些假设或状态有关…

那么基本上,
assertEquals
会因为值不同而失败吗?如果你强制阅读,它会起作用吗?那么,当您打印两次值时会得到什么呢?如果你的假设是正确的,那么应该打印两个不同的值。遗憾的是,没有,我试过了。但是,如果我引入一个类型为
double
的临时变量,您可以看到有两个不同的double值(我将更新上面的问题)。您是否可以共享
nativeInvokeWrapper()
的代码和相应的JNI部分,以便我们可以尝试运行?您可能触发了一些JIT错误。您的JVM版本和操作系统/体系结构是什么?使用+PrintAssembly运行时,是否可以发布结果?您还可以尝试使用+PrintNMethods或+printsubcode来更好地了解JVM/本机领域。