zoukankan      html  css  js  c++  java
  • jdk9+版本的bug

    今天从jvm大神"你假笨"的公众号上,看到一个jdk 9+版本的编译bug,记录一下:

    public class JavacEvalBug{
    
        private static String[] array = {""};
    
        static int test(){
            System.out.println("evaluated!");
            return 0;
        }
    
        public static void main(String[] args) {
            //相当于int index=test(); array[index] +="a";
            array[test()] += "a";
        }
    
    }
    

    test()方法里输出了一个固定字符串,上面这段代码,如果是在jdk8版本里,执行后,只会输出:evaluated! 一次(这符合预期,因为test()只调用了1次)

    但如果把jdk升级到jdk9或10,再次编译运行,evaluated!就会输出2次,即test()方法会多执行了1次,如果test()方法是复杂的业务逻辑,比如创建订单/库存扣减之类,这就成大问题了。

    原因在于jdk8与jdk9+的编译机制不同,javap -verbose JavacEvalBug  使用这个命令,可以看到编译细节:

      public static void main(java.lang.String[]);
        descriptor: ([Ljava/lang/String;)V
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=5, locals=1, args_size=1
             0: new           #5                  // class java/lang/StringBuilder
             3: dup
             4: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
             7: getstatic     #7                  // Field array:[Ljava/lang/String;
            10: invokestatic  #8                  // Method test:()I
            13: dup2_x1
            14: aaload
            15: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
            18: iconst_1
            19: invokevirtual #10                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
            22: invokevirtual #11                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
            25: aastore
            26: return
    

    jdk8上,从第10行看,只调用了1次,如果切换到jdk9+,则会变成:

      public static void main(java.lang.String[]);
        descriptor: ([Ljava/lang/String;)V
        flags: (0x0009) ACC_PUBLIC, ACC_STATIC
        Code:
          stack=4, locals=1, args_size=1
             0: getstatic     #5                  // Field array:[Ljava/lang/String;
             3: invokestatic  #6                  // Method test:()I
             6: getstatic     #5                  // Field array:[Ljava/lang/String;
             9: invokestatic  #6                  // Method test:()I
            12: aaload
            13: invokedynamic #7,  0              // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
            18: aastore
            19: return
          LineNumberTable:
    

    明显可以看到Method test:()I 调用了2次。具体详情分析,大神说是以后会详细分析,大概是字符串拼写的方式,jdk9以后做了变化。如果把string数组换成其它类型比如int

    public class JavacEvalBug{
        private static int[] array = {0};
    
        static int test(){
            System.out.println("evaluated!");
            return 0;
        }
    
        public static void main(String[] args) {
            //相当于int index=test(); array[index] +=1;
            array[test()] += 1;
        }
    }
    

    就正常了

    2018-07-28 更新,在jdk 10.0.2版本上,该bug已修复

  • 相关阅读:
    C#中任意类型数据转成JSON格式
    数据库用户映射到SQL Server登录名
    浅述WinForm多线程编程与Control.Invoke的应用
    Git错误一例
    提高VS2010/VS2012编译速度
    给有兴趣、有责任要讲课、分享的朋友推荐两本书
    中国剩余定理
    中国剩余定理
    洛谷1546 最短网路
    洛谷1111 修复公路
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/jdk-9-bug.html
Copyright © 2011-2022 走看看