这是 JVM 错误还是“预期行为”?
Posted
技术标签:
【中文标题】这是 JVM 错误还是“预期行为”?【英文标题】:Is this a JVM bug or "expected behavior"? 【发布时间】:2011-07-08 04:41:35 【问题描述】:我注意到一些意外行为(相对于我个人的期望而言是意外的),我想知道是否 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,并且这个过程应该以无限循环的形式重复。
当我实际运行这段代码时,我得到了不确定的结果。打印出来的结果往往是 50 万左右,但确切的值会有所不同。因此,当我认为它应该是一个无限循环时,循环不仅会终止,而且它似乎是随机终止的。怎么回事?
我的猜测是,这要么是 JVM 中的错误,要么是正在进行的许多时髦优化导致了这种预期行为。是哪个?
【问题讨论】:
这就是你的主要方法中的全部内容吗? @Michael:只是检查一下没有发生一些时髦的线程。在我的机器上它总是打印出 2147483640,但这仍然出乎意料。 我试了 3 次,结果在 300,000 和 500,000 之间 - 所以看起来它是特定于 VM 的(build 1.6.0_24-b07, 32bit linux) 程序永远不会在带有 HotSpot 1.6.0_24 的 32 位 Windows XP 上终止 Java 从未停止让我惊叹。对 OP +1 和对链接到 Oracle/Sung 错误的答案 +1。我最近最喜欢的是这个:***.com/questions/4949057 :) 【参考方案1】:已知错误。相关
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6196102
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6357214
和其他人。
我认为它们被认为是低优先级的修复,因为它们不会出现在现实世界中。
【讨论】:
【参考方案2】:这很奇怪。它肯定在某处看起来像一个错误。我每次使用相同的代码都会得到相同的结果,但是对代码的微小更改会改变结果。例如:
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)
【讨论】:
【参考方案3】:尝试添加System.out.println(count);
我想知道是否发生了优化,因为从不读取计数。
编辑 - 另一个答案提供了 Oracle 错误跟踪器中错误的链接。从中汲取灵感:
6196102 特别提到了与Integer.MAX_VALUE
相关的规范化错误。
Java 必须尝试优化循环,因为从未读取过 count
。
但是,这在实践中不太可能发生,因为:
Integer.MAX_VALUE
不太可能是循环保护
通常循环的工作一开始就不允许这种优化
【讨论】:
这至少使我的测试运行一致。所以这是一个优化问题?【参考方案4】:这似乎是一个循环优化,因为我观察到相同的结果,但如果我也打印出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(或类似)
【讨论】:
【参考方案5】: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)
按预期工作。无限循环
【讨论】:
以上是关于这是 JVM 错误还是“预期行为”?的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot 关闭端点应该关闭整个 JVM 进程,还是只关闭应用程序上下文?
WebClient 的 bodyToMono 关于空体预期行为
执行 2x 的脚本是 Chrome + Firefox 中的预期行为或错误?