zoukankan      html  css  js  c++  java
  • String源码中的"avoid getfield opcode"

    引言:

    之前一篇文章梳理了String的不变性原则,还提到了一段源码中注释"avoid getfield opcode",当时通过查阅资料发现,这是为了防止 getfield(获取指定类的实例域,并将其值压入到栈顶)这个操作码的执行,这篇文章想从字节码的角度去分析一下。


     

    先看一段代码吧

    /**
     * Created by chenqimiao on 16/11/29.
     */
    public class Main {
    
        public   char[] chars = new char[10];
    
        public void test() {
            System.out.println(chars[0]);
            System.out.println(chars[1]);
            System.out.println(chars[2]);
        }
    
        public static void main(String args[]) {
            Main m = new Main();
            m.test();
        }
    }
    

      执行 javap -c Main ,分析一下字节码,查看一下分析后生成的操作码:

    查阅"深入理解JVM虚拟机"一书中的虚拟机字节码指令表,试着分析一下test方法下面的code.

    4.获取指定的实例域,并将其值压入栈顶

    7.将int型0推送至栈顶

    8.将char数组指定索引的值推至栈顶

    9.调用实例方法

    总结一下的话,就是每次获取实例域 推到栈顶,然后推被操作的索引到栈顶,然后取到对应数组的指定索引的值推到栈顶,然后就是调用输出方法了。可以看到输出三次,getfield操作码就调用了三次,假想我们在遍历这个char数组,那象上述写法,要频繁调用getfield操作码了。

    我们学一下String源码中的写法,可能能改善一下这个问题。

    /**
     * Created by chenqimiao on 16/11/29.
     */
    public class Main {
    
        public   char[] chars = new char[10];
    
        public void test() {
            char[] chars = this.chars;
            System.out.println(chars[0]);
            System.out.println(chars[1]);
            System.out.println(chars[2]);
        }
    
        public static void main(String args[]) {
            Main m = new Main();
            m.test();
        }
    }
    

      

      执行 javap -c Main ,分析一下字节码,查看一下分析后生成的操作码:

    好了,我把实例变量的数组的引用赋给了一个局部引用了。

    我们还是分析一下test方法中的code把

    0.将第一个引用类型本地变量推送至栈顶(就是将局部变量引用chars放到栈顶)

    1.获取实例域的引用推到栈顶(实例变量的成员chars放到栈顶)

    4.将栈顶顶引用类型数值存入指定本地变量(就是把成员变量chars的引用给到局部变量的引用chars,这里是引用值拷贝,不是引用指向内存的值的拷贝)

    5.获取指定的实例域,并将其值压入栈顶

    8.将第二个引用类型本地变量推送至栈顶

    9.将int型0推到栈顶

    10.将char数组指定的索引的值压入到栈顶

    11.调用实例方法(输出)

    在14-20的过程中没有再发生"getfield"操作,而是用aload_1操作码将第二个本地引用(被赋值后的本地引用chars)推至栈顶,就可以执行接下来的一系列操作。

    到这里的话"avoid getfield opcode"的意思已经非常清楚明了,在遍历实例的char数组的时候,将实例数组的引用赋值给一个本地引用,不需要频繁调用操作用码"getfield",只需要在第一次对本地引用赋值的时候,调用一次getfield,接下来的遍历取值的时候,只需要将本地引用压入到栈顶。

     

     

     

  • 相关阅读:
    MFC中动态控件的创建与响应
    fseek函数
    fullPage.js插件用法(转发)
    二级联动
    ajax_异步交互-get/post方式
    02_数据类型转换-小结
    01_创建对象的三种方法
    分布式与集群
    FSM
    开发一个第三方库的一般性和团队特定规则
  • 原文地址:https://www.cnblogs.com/think-in-java/p/6130917.html
Copyright © 2011-2022 走看看