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 中“翻转”,所以加 1Integer.MAX_VALUE应该会导致Integer.MIN_VALUE. 由于Integer.MIN_VALUE仍然小于Integer.MAX_VALUE,因此循环将继续遍历负偶数整数。最终它会回到 0,并且这个过程应该以无限循环的形式重复。

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

我的猜测是,这要么是 JVM 中的错误,要么是正在进行的许多时髦优化导致了这种预期行为。它是哪一个?

4

5 回答 5

48

已知的错误。相关

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6196102

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6357214

和别的。

我认为它们被认为是修复的低优先级,因为它们不会出现在现实世界中。

于 2011-03-03T16:44:56.093 回答
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)
于 2011-03-03T16:30:31.640 回答
4

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

我想知道是否发生了优化,因为从不读取计数。

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

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

然而,这在实践中不太可能发生,因为:

  • Integer.MAX_VALUE是一个不太可能的循环守卫
  • 通常循环的工作一开始就不允许这种优化
于 2011-03-03T16:27:49.297 回答
2

这似乎是一个循环优化,因为我观察到相同的结果,但如果我也打印出来,count那么结果就会改变。

IE

    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 (或类似的)

于 2011-03-03T16:37:23.257 回答
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)

按预期工作。无限循环

于 2011-03-03T17:26:25.800 回答