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

相關文章
相關標籤/搜索