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已修复
出处: http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Java 手写Tomcat
1). 创建Java项目Tomcat 2). 创建Servlet接口 public interface IServlet { public void service(); } 3). 创建Tomcat核心主类 public class Core { @SuppressWarnings("resource") public static void main(String[] args) throws Exception { // 打印初始化 System.out.println("Tomcat: Hello! I'm Tomcat, and I'm in the initialization..."); // 睡眠3秒 Thread.sleep(3000); // 初始化完成 System.out.println("Tomcat: Now, I have finished the initializaion."); // 睡眠1秒 Thread.sleep(1000); // 启动 System.out.println("Tomcat: Now I will start the Serv...
- 下一篇
动态规划法(七)鸡蛋掉落问题(二)
上次我们讲到,我们的主人公丁丁由于用动态规划法解决了鸡蛋掉落问题(egg dropping problem)而获得了当地科学家的赏识。这不,正当丁丁还沉浸在解决问题的喜悦中,科学家又给丁丁出了一个难题: 假设有n个鸡蛋和d次尝试机会,那么,最多能探索多少层楼? 这无疑是鸡蛋问题的翻版,因为这两个问题实在太像了。丁丁没有犹豫,立马按照之前的想法开始思考: 用f(d,n)f(d,n)表示该问题的解。假设从k层楼扔下鸡蛋(k足够大),若鸡蛋碎了,则剩下n-1个鸡蛋,d-1次尝试机会,最多能向下探索f(d−1,n−1)f(d−1,n−1)层楼;若鸡蛋没碎,则剩下n个鸡蛋,d-1次尝试机会,最多能向上探索f(d−1,n)f(d−1,n)层楼,于是: f(d,n)=1+f(d−1,n−1)+f(d−1,n).f(d,n)=1+f(d−1,n−1)+f(d−1,n). 令 g(d,n)=f(d,n+1)−f(d,n)g(d,n)=f(d,n+1)−f(d,n),则: g(d,n)=f(d,n+1)−f(d,n)=[1+f(d−1,n)+f(d−1,n+1)]−[1+f(d−1,n−1)+f(...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- MySQL8.0.19开启GTID主从同步CentOS8
- Hadoop3单机部署,实现最简伪集群
- CentOS8编译安装MySQL8.0.19
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Mario游戏-低调大师作品