首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我的JVM要做一些运行时循环优化,并使我的代码错误?

为什么我的JVM要做一些运行时循环优化,并使我的代码错误?
EN

Stack Overflow用户
提问于 2013-06-18 10:04:04
回答 7查看 1.7K关注 0票数 10

请考虑以下java代码:

代码语言:javascript
复制
public int main() {
    int i = 1111;

    for (; rules(i) != true && i < Integer.MAX_VALUE; i++) {
        //LOG.debug("Testing i: " + i);
    }

    System.out.println("The mystery number is: " + i);

    return i;
}

protected boolean rules(int nb) {
    //...
}

我已经发现,即使for循环的连续值是true,当它的主体为空时,循环也将停止执行。

main的最终结果是错误的(i为16698,大约98%的时间,有时更高/更低)。

--如果我从循环体中取消对LOG语句的注释,则循环将继续运行,直到循环继续计算为false为止。

我使用的JVM是MacOS X VM1.6.0。

  • 它是否在执行某种运行时优化
  • 这个运行时优化是否可以被认为是一个bug?
  • 还是说Java规范中的某个地方说,为了继续计算,不应该运行功能操作?

ps:完整的代码源代码+其单元测试可在这里获得:https://gist.github.com/dirtyhenry/5804130

更新:

  • 我只通过junit运行代码。junit会对这种行为负责吗?

更新2:

代码语言:javascript
复制
java -version

返回:

代码语言:javascript
复制
java version "1.6.0_51"
Java(TM) SE Runtime Environment (build 1.6.0_51-b11-456-11M4508)
Java HotSpot(TM) 64-Bit Server VM (build 20.51-b01-456, mixed mode)
EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2013-06-18 12:12:38

我看到了一些关于SO to循环优化的引用,只有在超过10000次迭代之后才会发生。也许这就是为什么“魔法数字”经常在16000左右?

这里有个很好的讨论

JVM option to optimize loop statements

票数 2
EN

Stack Overflow用户

发布于 2013-08-15 10:19:53

我在这里有一个类似的问题:Near empty Java For-Loop acts strange --您应该尝试使用JVM1.7或尝试使用一个while循环:

代码语言:javascript
复制
public int main() {
    int i = 1111;

    while(i < Integer.MAX_VALUE){
        if (!rules(i)) {
            break;
        }
        i++
    }

    System.out.println("The mystery number is: " + i);

    return i;
}
票数 3
EN

Stack Overflow用户

发布于 2013-08-16 09:09:17

我用jdk 1.7.0_21测试了您的代码,它返回了与LOG.debug语句相同的结果,即942210。

代码语言:javascript
复制
    int i = 0;
    for( ; !rules(i) && i < Integer.MAX_VALUE ; i++ ){
        //LOG.debug( "test " + i );
    }
    System.out.println( "i is " + i );

我还打印出了两个版本的字节码(空循环)。

代码语言:javascript
复制
   0: aload_0       
   1: invokespecial #3                  // Method java/lang/Object."<init>":()V
   4: iconst_0      
   5: istore_1      
   6: aload_0       
   7: iload_1       
   8: invokevirtual #4                  // Method rules:(I)Z
  11: ifne          26
  14: iload_1       
  15: ldc           #5                  // int 2147483647
  17: if_icmpge     26
  20: iinc          1, 1
  23: goto          6
  26: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
  29: new           #7                  // class java/lang/StringBuilder
  32: dup           
  33: invokespecial #8                  // Method java/lang/StringBuilder."<init>":()V
  36: ldc           #9                  // String i is 
  38: invokevirtual #10                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  41: iload_1       
  42: invokevirtual #11                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  45: invokevirtual #12                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  48: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  51: return 

带调试打印输出的循环

代码语言:javascript
复制
   0: aload_0       
   1: invokespecial #3                  // Method java/lang/Object."<init>":()V
   4: iconst_0      
   5: istore_1      
   6: aload_0       
   7: iload_1       
   8: invokevirtual #4                  // Method rules:(I)Z
  11: ifne          48
  14: iload_1       
  15: ldc           #5                  // int 2147483647
  17: if_icmpge     48
  20: new           #6                  // class java/lang/StringBuilder
  23: dup           
  24: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
  27: ldc           #8                  // String test 
  29: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  32: iload_1       
  33: invokevirtual #10                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  36: invokevirtual #11                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  39: invokestatic  #12                 // Method LOG.debug:(Ljava/lang/String;)V
  42: iinc          1, 1
  45: goto          6
  48: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
  51: new           #6                  // class java/lang/StringBuilder
  54: dup           
  55: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
  58: ldc           #14                 // String i is 
  60: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  63: iload_1       
  64: invokevirtual #10                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  67: invokevirtual #11                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  70: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  73: return 

如您所见,循环结构是相同的。20 - 39只是构造字符串并调用LOG.debug。

因此,这可能是jdk的问题。尝试1.7,它应该有效。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17166047

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档