我遇到了一个相当奇怪的问题,当运行Java 8时,我可以创建这个问题。该问题表现为JVM本身发生某种定时错误。它是间歇性的,但在我的测试环境中很容易重现。问题是,在某些情况下,明确设置的数组值被销毁并替换为0.0。具体来说,在下面的代码中,array[0]
在执行new Double(r.nextDouble());
后评估为0.0。然后,如果您立即再次查看array[0]
的内容,它现在显示为正确的值1.0。运行此测试用例的示例输出如下:
claims array[0] != 1.0....array[0] = 1.0
claims array[0] now == 1.0...array[0] = 1.0`
我正在运行64位的Windows 7,并且能够从Eclipse中或者通过命令行编译时,使用JDKs 1.8_45、1.8_51和1.8_60来重现这个问题。但是在运行1.7_51时,我无法出现这个问题。另外,在另一台64位的Windows 7电脑上也得到了相同的结果。
这个问题出现在一个庞大而复杂的软件中,但是我已经将其压缩到了几行代码中。下面是一个小的测试用例,它演示了这个问题。它看起来非常奇怪,但是似乎所有的部分都是必要的才能引起错误。不需要使用Random - 我可以将所有的r.nextDouble()替换成任何double值并演示出问题。有趣的是,如果将someArray [0] = .45;替换成someArray [0]= r.nextDouble(); ,我就无法复制该问题(尽管.45没有特殊之处)。Eclipse调试也没办法 - 它会改变时间,使得它不再出现。即使一个恰当放置的System.err.println()语句也会导致该问题不再出现。
同样,这个问题是间歇性的,所以为了复制该问题,您可能需要运行此测试用例多次。我最多运行了大约10次,才得到了上面显示的输出。在Eclipse中,我在运行后等待一两秒钟,如果没有发生,就杀掉它。从命令行也是一样 - 运行它,如果不出现问题,请使用CTRL+C退出并重试。看起来如果它要发生,它发生得非常快。
我遇到过类似这样的问题,但它们都是线程问题。我无法弄清楚这里发生了什么 - 我甚至查看了字节码(顺便说一下,在1.7_51和1.8_45之间是相同的)。你们有什么想法吗?
import java.util.Random;
public class Test {
Test(){
double array[] = new double[1];
Random r = new Random();
while(true){
double someArray[] = new double[1];
double someArray2 [] = new double [2];
for(int i = 0; i < someArray2.length; i++) {
someArray2[i] = r.nextDouble();
}
// for whatever reason, using r.nextDouble() here doesn't seem
// to show the problem, but the # you use doesn't seem to matter either...
someArray[0] = .45;
array[0] = 1.0;
// commented out lines also demonstrate problem
new Double(r.nextDouble());
// new Float(r.nextDouble();
// double d = new Double(.1) * new Double(.3);
// double d = new Double(.1) / new Double(.3);
// double d = new Double(.1) + new Double(.3);
// double d = new Double(.1) - new Double(.3);
if(array[0] != 1.0){
System.err.println("claims array[0] != 1.0....array[0] = " + array[0]);
if(array[0] != 1.0){
System.err.println("claims array[0] still != 1.0...array[0] = " + array[0]);
}else {
System.err.println("claims array[0] now == 1.0...array[0] = " + array[0]);
}
System.exit(0);
}else if(r.nextBoolean()){
array = new double[1];
}
}
}
public static void main(String[] args) {
new Test();
}
}
new Double(...)
是否必需?在实际代码中,我不希望发现这种情况。@PM77-1:将“1.0”的整数值存储在“double”中永远不应导致此类问题,因为它可以表示而不损失精度。如果“==”给出错误的结果,则更可能由于JVM中的某些错误而使用了装箱值。 - Axel-XX:-TieredCompilation
或者-XX:-EliminateAllocations
很可能是一个可接受的解决方法,不会显著降低性能。 - apangin