棧幀的內部結構--局部變量表(Local Variables)


每個棧幀中包含:

  • 局部變量表(Local Variables)
  • 操作數棧(Opreand Stack) 或表達式棧
  • 動態鏈接 (Dynamic Linking) (或指向運行時常量的方法引用)
  • 動態返回地址(Return Address) (或方法正常退出或者異常退出的引用的定義)
  • 一些附加信息

局部變量表

  • 局部變量表也被稱之為局部變量數據組或本地變量表
  • 定義為一個數字數組,主要用戶存儲方法參數和定義在方法體內的局部變量,這些數據類型包括各類基本數據類型、對象引用(reference),以及returnAddress 類型
  • 由於局部變量表示建立在線程的棧上,是線程的私有數據,因此不存在數據安全問題
  • 局部變量表所需要的容量大小是在編譯期確定下來的,並保存在方法的Code屬性的maximun local variables數據項中,在方法運行期間時不會改變局部變量表的大小的
  • 方法嵌套調用的次數由棧的大小決定,一般來說,棧越大,方法嵌套調用次數越多,對於一個函數而言,他的參數和局部變量越多,使得局部變量表膨脹,它的棧就越大,以滿足方法調用所需傳遞的信息增大的需求,進而函數調用就會占更多的棧空間,導致其嵌套調用次數就會減少
  • 局部變量表中的變量只在當前方法調用中有效。在方法執行時,虛擬機通過使用局部變量表完成參數值到參數變量列表的傳遞過程,當方法調用結束后,隨着方法棧的銷毀,局部變量表也會隨之銷毀

局部變量表的存儲單元Slot(變量槽)

  • 參數值的存放總是在局部變量數據的index0開始,到數組長度-1的索引結束
  • 局部變量表,最基本的存儲單元是Slot(變量槽)
  • 局部變量表中存放編譯期可知的各種基本數據類型(8種)、引用類型(reference)、returnAdderss類型的變量
  • 在局部變量表中,32位以內的類型只占一個slot(包括returnAdderss類型)64位的類型(long和double)占用兩個slot
    • byte、short、char在存儲前被轉換為int,boolean也被准換為int,0為false,1為true
    • long和double則占據兩個slot
  • JVM會為局部變量表中的每一個slot都分配一個訪問索引,通過這個索引即可成功的訪問到局部變量表中指定的局部變量值
  • 當一個實例方法被調用的時候,它的方法參數和方法體內部定義的局部變量表將會按照順序被復制到局部變量表中的每一個slot上
  • 如果需要訪問局部變量表中一個64bit的局部變量值時,只需要使用前一個索引即可
  • 如果當前幀是由構造方法或者實例方法創建的,那么該對象引用this將會被存放在index為0的slot處,其余的參數按照參數表順序繼續排列

 

 各個類型占用slot圖示

 

  • slot也是可以進行重復利用的,即如果一個局部變量過了其作用域,那么在其作用域之后申明的新的局部變量就很有可能會復用過期的局部變量的槽位,從而達到節約資源的目的。主要的運用方式如下所示,其中{}外作用域就結束了
    //出了大括號就不能用了
    public void LocalVar(){
            {
                int a= 0;
                System.out.println(a);
            }
            //此時b就會復用a的槽位
            int b=0;
    }

常見問題

Q:為什么static中不能調用this方法

A:因為this的索引只存在構造方法和實例方法的局部變量表中,而static是在初始化方法<clinit>中進行初始化的,里面沒有保存this變量的索引

Q:變量的分類

A:

    • 按照數據類型分類
      • 基本數據類型
      • 引用數據類型(對象)
    • 按照在類中的位置分類
      • 成員變量:類中變量,在使用前,都經歷默認初始化賦值
        • 類變量,Linking的prepare階段,給類變量默認賦值–>initial階段,給類變量顯示賦值,即靜態代碼塊賦值
        • 實例變量,隨着對象的創建,會在堆空間中分配實例變量空間,並進行默認賦值
      • 局部變量:方法中的變量。在使用時必須進行顯示的賦值,否則編譯不通過

Q:局部變量與成員變量的對比

A:

    • 參數表分配完畢以后,在根據方法體內定義的變量的順序和作用域分配
    • 我們知道類變量表有兩次初始化的機會,第一次是在“准備階段”,執行系統初始化,對類變量設置零值,另一次是在“初始化”階段,賦予變量在代碼中定義的初始值
    • 和類變量初始化不同的是,局部變量表不存在系統初始化過程中,這就意味着一旦定了局部變量則必須認為的初始化,否則無法使用
public void test(){
    int i;
    Systme.out.println(i);
    //這種是編譯不通過的
}

其他

  • 在棧幀中,與性能調優關系最為密切的部分就是前面提到的局部變量表,在方法執行時,虛擬機使用局部變量表完成方法的傳遞
  • 局部變量表中的變量也是重要的垃圾回收根節點,只要被局部變量表中的直接或者間接引用的對象都不會被回收
  • 也可以新建局部對象

 

附:JVM學習目錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM