这是 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 中的预期行为或错误?

pytz 和 datetime 奇怪的行为 - 可能的错误?

SwiftUI 中的 Picker 适用于 ForEach 的一个版本,但不适用于另一个版本 - 错误或预期行为?