我有一个 JUnit 测试,看起来或多或少是这样的:
double doubleValue = 100.0 + 1E-14;
long longValue = nativeInvokeWrapper(doubleValue, ...);
assertEquals(doubleValue, Double.longBitsToDouble(longValue));
背景
该函数nativeInvokeWrapper
调用另一个 Java 函数,后者又调用一个 JNI 函数,该函数最终调用一个“C”函数,作为参数__stdcall
传递。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(使用 运行 JVM -Xint
),一切正常。所以这与一些特定于 JIT 编译代码的假设或状态有关......