LocalVariableTable之 Slot 复用

LocalVariableTable中的 Slot, 是存在复用现象的,这个我早就知道,可是,不太清楚是如何复用的。java

  • Java语言规范与JVM规范都没有对Java语言具体要如何使用JVM的局部变量slot作太多限制,只是规定了参数要从下标为0开始的局部变量区传递而已。做用域不重叠的局部变量之间是否必定要复用局部变量区的slot,这纯粹是实现细节——复用也能够,不复用也彻底符合规范。因此这种事情只能针对某个具体实现来讨论。假如题主是用Oracle/Sun JDK或者OpenJDK,那么用JDK自带的javap工具来看看不一样样子的源码生成怎样的字节码就能够感觉到差异了。
  • 在Oracle/Sun JDK与OpenJDK里的javac实现,分配局部变量slot的方式很是死板,纯粹看几个因素:
  • 声明顺序:先到先得;
  • 做用域:进入做用域时抢最靠前得坑,一离开做用域就放开这个坑,让后面的做用域的变量能够占坑;
  • 类型:long与double占俩相邻slot,其它类型占一个slot。

我用的Java版本是Hotspot ,以下,也是有这样的现象的。工具

java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)测试

一个关键点是做用域,什么是java中变量的做用域?它范围是,从定义变量的那一行开始,到对应的代码块结束的那一行。那么什么是代码块呢? 包含它的花括号的整个部分就是 一个代码块。ui

 

看一个例子,以下的代码:spa

    private static void test1() throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        for (int i = 0; i < 3; i++) {
            int ia = 1;
            long long1 = 2;
            int ib = 3;
            long long2 = 555;
            System.out.println(" over = ");
        }

        ArrayList<Integer> array=new ArrayList<Integer>();
        array.add(1);
        for (int i=0;i<array.size();i++) {
            System.out.println(array.get(i));
            Integer ia=array.get(i);
            Integer ib=array.get(i);
            System.out.println(ia);
        }
//        int i = ia + ib;
    }

javap获得的字节码是:code

 LocalVariableTable:
        Start  Length  Slot  Name   Signature
         9      20     1       ia   I
        13      16     2    long1   J
        16      13     4       ib   I
        21       8     5    long2   J
         2      33     0        i   I
        82      16     2       ia   Ljava/lang/Integer;
        91       7     3       ib   Ljava/lang/Integer;
        54      50     1        i   I
        43      62     0    array   Ljava/util/ArrayList;

 

Slot 值出现了重复的0,1,2... ,可见,Slot就是出现了复用。Slot的占用是按照变量在源码出现的顺序来的。 不过,奇怪的是,从上面的信息看来,Slot并非按字节码信息LocalVariableTable表的顺序来的,Start,Length,Name,Signature都不是的。 ia占用1个slot,long1是2个(尽管long1的起始的slot仍是2,可是咱们从ib 的起始slot能够推测),long2 起始的slot是5,那么它占用了几个slot呢?从上面的字节码信息,咱们并看不出上面东西呢,咱们只能根据经验推测, 经验就是 blog

long与double占俩相邻slot,其它类型占一个slot作用域

若是非要看到long2 占用了几个slot,那么就须要再在其对应的做用域中long2 后面建立另外的变量,那么而后就能够经过它后面的变量的起始slot 推测了。get

另外,我测试的时候,发现若是变量定义的位置是做用域最后一行的话,也就是说若是定义了变量,后面没有其余代码了,那么它是不会出如今LocalVariableTable表中的。为何会这样?我想是由于这个时候它就彻底无用了吧。若是要让它出如今LocalVariableTable表中,那么只要在其后面随便写点什么代码就行了!源码

 

须要注意的是,若是咱们的方法,整个就一个做用域,是不会出现slot复用的,由于没法复用啊,一个方法什么状况会出现多个做用域呢? 其实很简单,一个while循环,或者for,或者if.. else,或者switch等等, 还有就是单单一个 花括号 包围也能够。

 

参考:

https://www.zhihu.com/question/41694588

相关文章
相关标签/搜索