2

我有一个 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.

关键是 的预期返回值nativeInvokeWrapperlong按位等于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 编译代码的假设或状态有关......

4

0 回答 0