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

时间:2013-07-28 20:58:12

标签: 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函数,该函数最终调用__stdcall“C”函数,并将doubleValue作为参数传递。 “C”函数返回一个64位值,该值按位等于它接收的double参数,并且此返回值将传播出去,直到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()方法之前强制“读取”longValue一样,状态损坏问题就会消失。

帮助!

我正在寻找的是关于如何调试/确定根本原因的想法。如上所述,单步执行常规Eclipse调试器是没有用的,因为好像阅读-Xint可以解决问题。

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

更新:如果我关闭JIT(使用{{1}}运行JVM),一切正常。所以这与JIT编译代码的某些假设或状态有关...

0 个答案:

没有答案