我有一个看起来或多或少的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
。
我的本机函数可能会以某种微妙的方式破坏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编译代码的某些假设或状态有关...