这是一个JVM的错误或“预期的行为”?
我注意到一些意想不到的行为(与我个人的期望相关),我想知道如果JVM中有一个错误,或者这是一个附带案例,我不明白什么是什么细节应该会发生。 假设我们在主要方法中有以下代码:
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中的一个错误,或者有很多时髦的优化,使得这种预期的行为。 这是哪个?
已知的错误。 相关
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6196102
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6357214
和别的。
我认为他们被认为是不重要的,因为他们不是现实世界。
这是奇怪的。 它肯定看起来像一个错误的地方。 每次使用相同的代码我都会得到相同的结果,但对代码的微小更改会改变结果。 例如:
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和真实的
而这个:
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并且是正确的。
非常非常奇怪
(这是在Linux上运行的OpenJDK 1.6虚拟机。)
编辑:在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)
尝试添加System.out.println(count);
我不知道是否有优化发生,因为计数是从来没有读过。
编辑 – 另一个答案给了Oracle的错误跟踪器错误的链接。 从中得出:
- 6196102特别提到了
Integer.MAX_VALUE
有一个规范化错误。 - Java必须尝试优化循环,因为从不读取
count
。
但是,这在实践中不太可能发生,因为:
-
Integer.MAX_VALUE
是一个不太可能的循环后卫 - 通常循环做的工作,首先不会允许这种优化
这似乎是一个循环优化,因为我观察到相同的结果,但如果我也打印出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(或类似)
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)
按预期工作。 无限循环