zoukankan      html  css  js  c++  java
  • LocalVariableTable之 Slot 复用

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

    • 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中变量的作用域?它范围是,从定义变量的那一行开始,到对应的代码块结束的那一行。那么什么是代码块呢? 包含它的花括号的整个部分就是 一个代码块。

    看一个例子,如下的代码:

        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得到的字节码是:

     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呢?从上面的字节码信息,我们并看不出上面东西呢,我们只能根据经验推测, 经验就是 

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

    如果非要看到long2 占用了几个slot,那么就需要再在其对应的作用域中long2 后面创建另外的变量,那么然后就可以通过它后面的变量的起始slot 推测了。

    另外,我测试的时候,发现如果变量定义的位置是作用域最后一行的话,也就是说如果定义了变量,后面没有其他代码了,那么它是不会出现在LocalVariableTable表中的。为什么会这样?我想是因为这个时候它就完全无用了吧。如果要让它出现在LocalVariableTable表中,那么只要在其后面随便写点什么代码就好了!

    需要注意的是,如果我们的方法,整个就一个作用域,是不会出现slot复用的,因为无法复用啊,一个方法什么情况会出现多个作用域呢? 其实很简单,一个while循环,或者for,或者if.. else,或者switch等等, 还有就是单单一个 花括号 包围也可以。

    参考:

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

  • 相关阅读:
    Json.Net学习笔记(八) 序列化的回调方法
    PowerDesigner 使用的一些技巧(转)
    Json.Net学习笔记(十三) 缩小序列化Json的大小
    Json.Net学习笔记(十四) JSON的部分序列化
    MSDTC服务配置 今天碰到的情况
    Json.Net学习笔记(十一) CustomCreationConverter
    让工作自动化
    Json.Net学习笔记(十二) 协议解析
    Json.Net学习笔记(九) 异常处理
    通过PB认证
  • 原文地址:https://www.cnblogs.com/FlyAway2013/p/10476021.html
Copyright © 2011-2022 走看看