这是JVM错误还是“预期行为”?


70

我注意到了一些意外的行为(相对于我的个人期望而言是意外的),我想知道是否是JVM中存在错误,或者这可能是一种边缘情况,在这种情况下我不了解某些确切的细节应该发生。假设我们自己在main方法中具有以下代码:

int i;
int count = 0;
for(i=0; i < Integer.MAX_VALUE; i+=2){
  count++;
}
System.out.println(i++);

天真的期望是这样会印刷Integer.MAX_VALUE-1,最大的甚至可以代表int。但是,我认为整数算术应该在Java中“翻转”,因此将1加到会Integer.MAX_VALUE导致Integer.MIN_VALUE。由于Integer.MIN_VALUE仍然小于Integer.MAX_VALUE,因此循环将循环遍历负数甚至整数。最终它将回到0,并且此过程应作为无限循环重复进行。

当我实际运行此代码时,会得到不确定的结果。打印的结果往往大约为一百万,但是确切的值却有所不同。因此,当我认为循环应该是无限循环时,循环不仅终止了,而且似乎随机终止了。这是怎么回事?

我的猜测是,这要么是JVM中的错误,要么是正在进行许多时髦的优化,从而产生了预期的行为。哪有


这就是您的主要方法吗?
乔恩·斯基特

@Michael:只是检查一下没有什么时髦的线程。在我的机器上,它总是打印2147483640,但这仍然是意外的。
乔恩·斯基特

2
我尝试了3次,结果在300,000到500,000之间,结果不同-看起来它是特定于VM的(内部版本1.6.0_24-b07,32位linux)
Matthew Gilliard

程序永远不会在带有HotSpot 1.6.0_24的32位Windows XP上终止
Jeremy

1
Java从不停止让我惊奇。+1链接到OP,+ 1链接到Oracle / Sung错误的答案。我最近最喜欢的一个是:stackoverflow.com/questions/4949057 :)
SyntaxT3rr0r 2011年

Answers:



15

真奇怪 它肯定看起来像是某个地方的错误。每次使用相同的代码,我都会得到相同的结果,但是对代码的微不足道的更改会改变结果。例如:

public class Test {
  public static void main(String[] args) {
    int i;
    int count = 0;
    for (i = 0; i < Integer.MAX_VALUE; i+=2) {
      count++;
    }
    System.out.println(i);
    System.out.println(i < Integer.MAX_VALUE);
  }
}

...总是打印2147483640和true

而这:

public class Test {
  public static void main(String[] args) {
    int i;
    for (i = 0; i < Integer.MAX_VALUE; i+=2) {
    }
    System.out.println(i);
    System.out.println(i < Integer.MAX_VALUE);
  }
}

始终打印-2147483648和true。

非常非常奇怪

(在Linux上运行OpenJDK 1.6 VM。)

编辑:在Windows 7上运行OpenJDK 1.7,我没有看到问题:

java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b78)
Java HotSpot(TM) Client VM (build 17.0-b05, mixed mode, sharing)

4

尝试添加 System.out.println(count);

我不知道是否存在优化,因为从不读取计数。

编辑-另一个答案提供了指向Oracle错误跟踪器中错误的链接。从中得出:

  • 6196102特别提到相关的规范化错误Integer.MAX_VALUE
  • Java必须尝试优化循环,因为count从不读取。

但是,这在实践中不太可能发生,因为:

  • Integer.MAX_VALUE 是不太可能的循环后卫
  • 通常情况下,循环的工作一开始就不允许这种优化

这至少使我的测试运行一致。那么这是一个优化问题吗?
Matthew Gilliard

2

当我观察到相同的结果时,这似乎是循环优化,但是如果我也打印出count结果,则结果会更改。

    int i;
    int count = 0;
    for(i=0; i < Integer.MAX_VALUE; i+=2){
      count++;
    }
    System.out.println(count);
    System.out.println(i++);

产生2147483638,而原始代码产生457158(或类似代码)


0
java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Java HotSpot(TM) Client VM (build 17.1-b03, mixed mode, sharing)

按预期工作。无限循环

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.