天天看點

知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題

虛拟機棧

  • 虛拟機棧概述
    • 記憶體中的棧與堆
    • Java虛拟機棧是什麼?
    • 虛拟機棧的生命周期
    • 虛拟機棧的作用
    • 棧的特點
    • 相關問題
      • 棧中可能出現的異常
      • 設定棧記憶體的大小
  • 虛拟機棧的存儲機關
    • 虛拟機棧存儲什麼?
    • 虛拟機棧的運作原理
  • 虛拟機棧的内部結構
    • 局部變量表
      • 靜态變量與局部變量的對比:
    • 操作數棧
    • ==動态連結(或指向運作時常量池的方法引用)==
      • 為什麼要用常量池呢?
    • 方法傳回位址
    • 一些附加資訊:
  • 相關問題

虛拟機棧概述

記憶體中的棧與堆

首先棧是運作時的機關,而堆是存儲的機關

棧解決程式的運作問題,即程式如何執行,或者說如何處理資料。

堆解決的是資料存儲的問題,即資料怎麼放,放哪裡。

知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題

Java虛拟機棧是什麼?

Java虛拟機棧(Java Virtual Machine Stack),早期也叫Java棧。每個線程在建立時都會建立一個虛拟機棧,其内部儲存一個個的棧幀(Stack Frame),對應着一次次的Java方法調用,棧是線程私有的。

注意:方法執行裡也是借助一個棧來操作——操作數棧,用來儲存操作數。

虛拟機棧的生命周期

生命周期和線程一緻,也就是線程結束了,該虛拟機棧也銷毀了。

虛拟機棧的作用

主管Java程式的運作,它儲存方法的局部變量(8 種基本資料類型、對象的引用位址)、部分結果,并參與方法的調用和傳回。

棧的特點

棧是一種快速有效的配置設定存儲方式,通路速度僅次于程式計數器。JVM直接對Java棧的操作隻有兩個:

每個方法執行,伴随着進棧(入棧、壓棧);執行結束後的出棧工作。

對于棧來說不存在垃圾回收問題(棧存在溢出的情況)

知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題

相關問題

棧中可能出現的異常

Java 虛拟機規範允許Java棧的大小是動态的或者是固定不變的。

如果采用固定大小的Java虛拟機棧,那每一個線程的Java虛拟機棧容量可以線上程建立的時候獨立標明。

如果線程請求配置設定的棧容量超過Java虛拟機棧允許的最大容量,Java虛拟機将會抛出一個StackoverflowError 異常。

如果Java虛拟機棧可以動态擴充,并且在嘗試擴充的時候無法申請到足夠的記憶體,或者在建立新的線程時沒有足夠的記憶體去建立對應的虛拟機棧,那Java虛拟機将會抛出一個 OutofMemoryError 異常。

設定棧記憶體的大小

我們可以使用參數 -Xss 選項來設定線程的最大棧空間,棧的大小直接決定了函數調用的最大可達深度。

-Xss1024m // 棧記憶體為 1024MBS

-Xss1024k // 棧記憶體為 1024KB

知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題
知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題
知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題

虛拟機棧的存儲機關

虛拟機棧存儲什麼?

每個線程都有自己的棧,棧中的資料都是以棧幀(Stack Frame)的格式存在。

在這個線程上正在執行的每個方法都各自對應一個棧幀(Stack Frame)。

棧幀是一個記憶體區塊,是一個資料集,維系着方法執行過程中的各種資料資訊。

虛拟機棧的運作原理

1、JVM直接對Java棧的操作隻有兩個,就是對棧幀的壓(入)棧和出棧,遵循先進後出(後進先出)原則

2、在一條活動線程中,一個時間點上,隻會有一個活動的棧幀。

(1)即隻有目前正在執行的方法的棧幀(棧頂棧幀)是有效的這個棧幀被稱為目前棧幀(Current Frame)

(2)與目前棧幀相對應的方法就是目前方法(Current Method)

(3)定義這個方法的類就是目前類(Current Class)

3、執行引擎運作的所有位元組碼指令隻針對目前棧幀進行操作。

4、如果在該方法中調用了其他方法,對應的新的棧幀會被建立出來,放在棧的頂端,成為新的目前幀。

5、不同線程中所包含的棧幀是不允許存在互相引用的,即不可能在一個棧幀之中引用另外一個線程的棧幀。

6、如果目前方法調用了其他方法,方法傳回之際,目前棧幀會傳回此方法的執行結果給前一個棧幀,接着,虛拟機會丢棄目前棧幀,使得前一個棧幀重新成為目前棧幀。

7、Java方法有兩種傳回函數的方式,一種是正常的函數傳回,使用return指令;另外一種是抛出異常,但不管使用哪種方式,都會導緻棧幀被彈出

知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題

當方法2結束,方法1變成目前方法。

主線程方法1結束整個線程就結束了,目前虛拟機棧也就結束了。

虛拟機棧的内部結構

1、局部變量表(Local Variables)

2、操作數棧(Operand Stack)(或表達式棧)

3、動态連結(Dynamic Linking)(或指向運作時常量池的方法引用)

4、方法傳回位址(Return Address)(或方法正常退出或者異常退出的定義)

5、一些附加資訊

知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題

并行每個線程下的棧都是私有的,是以每個線程都有自己各自的棧,并且每個棧裡面都有很多棧幀,棧幀的大小主要由局部變量表和操作數棧決定的。

局部變量表

1、局部變量表:Local Variables,被稱之為局部變量數組或本地變量表

2、定義為一個數字數組,主要用于存儲方法參數和定義在方法體内的局部變量,這些資料類型包括各類基本資料類型、對象引用(reference),以及returnAddress類型。

3、由于局部變量表是建立線上程的棧上,是線程的私有資料,是以不存在資料安全問題

4、局部變量表所需的容量大小是在編譯期确定下來的,并儲存在方法的Code屬性的maximum local variables資料項中。在方法運作期間是不會改變局部變量表的大小的。

5、方法嵌套調用的次數由棧的大小決定。一般來說,棧越大,方法嵌套調用次數越多。

對一個函數而言,它的參數和局部變量越多,使得局部變量表膨脹,它的棧幀就越大,以滿足方法調用所需傳遞的資訊增大的需求。進而函數調用就會占用更多的棧空間,導緻其嵌套調用次數就會減少。

6、局部變量表中的變量隻在目前方法調用中有效。

在方法執行時,虛拟機通過使用局部變量表完成參數值到參數變量清單的傳遞過程。

當方法調用結束後,随着方法棧幀的銷毀,局部變量表也會随之銷毀。

知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題

javap -verbose LocalVariablesTest.class

在編譯期間,局部變量的個數、每個局部變量的大小都已經被記錄下來

是以局部變量表所需的容量大小是在編譯期确定下來的

靜态變量與局部變量的對比:

變量的分類:

1、按照資料類型分:

  • 基本資料類型
  • 引用資料類型

2、按照在類中聲明的方式分:

  • 成員變量:類static變量和執行個體變量

    1、類static變量:

    linking的prepare階段:給類變量預設指派

    initial階段:給類變量顯式指派即靜态代碼塊指派

    2、執行個體變量:随着對象的建立,會在堆空間中配置設定執行個體變量空間,并進行預設指派

  • 局部變量:在使用前,必須要進行顯式指派的!否則,編譯不通過
    知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題

操作數棧

操作數棧:Operand Stack

1、每一個獨立的棧幀除了包含局部變量表以外,還包含一個後進先出的操作數棧,也可以稱之為表達式棧(Expression Stack)

2、操作數棧,在方法執行過程中,根據位元組碼指令,往棧中寫入資料或提取資料,即入棧(push)和 出棧(pop)

3、某些位元組碼指令将值壓入操作數棧,其餘的位元組碼指令将操作數取出棧。使用它們後再把結果壓入棧,比如:執行複制、交換、求和等操作

4、主要用于儲存計算過程的中間結果,同時作為計算過程中變量臨時的存儲空間。

知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題

動态連結(或指向運作時常量池的方法引用)

1、在Java源檔案被編譯到位元組碼檔案中時,所有的變量和方法引用都作為符号引用(Symbolic Reference)儲存在class檔案的常量池裡

2、比如:描述一個方法調用了另外的其他方法時,就是通過常量池中指向方法的符号引用來表示的,那麼動态連結的作用就是為了将這些符号引用轉換為調用方法的直接引用

知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題

為什麼要用常量池呢?

因為在不同的方法,都可能調用常量或者方法,是以隻需要存儲一份,然後記錄其引用即可,節省了空間。

方法類似于做菜,需要用到各種配料醬油、味精、鹽等,編譯的時候就像菜單;寫的"味精",相當于符号引用(位元組碼中看到的ConstantPool都是符号引用);當真正炒菜的時候就是運作時;要去拿真正的味精,變成直接引用。

方法傳回位址

存放調用該方法的pc寄存器的值,方法結束之後要回調調用該方法的位置繼續往下執行。

知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題

一些附加資訊:

棧幀中還允許攜帶與Java虛拟機實作相關的一些附加資訊。例如:對程式調試提供支援的資訊。

相關問題

1、舉例棧溢出的情況?

如果線程請求配置設定的棧容量超過Java虛拟機棧允許的最大容量,Java虛拟機将會抛出一個StackoverflowError 異常。

可以通過 -Xss 設定棧的大小

2、調整棧大小,就能保證不出現溢出麼?

不能保證不溢出,畢竟記憶體是有限的而不是無限大。

3、配置設定的棧記憶體越大越好麼?

不是,一定程度減少了棧溢出的機率,但是會擠占其它的線程空間,因為整個虛拟機的記憶體空間是有限的,會出現OOM(OutofMemory 記憶體溢出)

4、垃圾回收是否涉及到虛拟機棧?

不會。Java虛拟機棧隻有入棧和出棧,銷毀就是出棧

5、方法中定義的局部變量是否線程安全?何為線程安全?

(1)如果隻有一個線程才可以操作此資料,則必是線程安全的。

(2)如果有多個線程操作此資料,則此資料是共享資料。如果不考慮同步機制的話,會存線上程安全問題。

具體問題具體分析:

如果對象是在内部産生,并在内部消亡,沒有傳回到外部,那麼它就是線程安全的,反之則是線程不安全的。

/**
 * 方法中定義的局部變量是否線程安全?具體情況具體分析
 *   何為線程安全?
 *      如果隻有一個線程才可以操作此資料,則必是線程安全的。
 *      如果有多個線程操作此資料,則此資料是共享資料。如果不考慮同步機制的話,會存線上程安全問題。
 */
public class StringBuilderTest {
    int num = 10;
 
    //s1的聲明方式是線程安全的,方法調用壓入棧幀,隻在這個線程通路
    //定義的全局變量int num = 10;可能被多個線程通路就是線程不安全的
    public static void method1(){
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
        //...
    }
    //sBuilder的操作過程:是線程不安全的,sBuilder從外面傳遞過來,可能被多個線程調用
    public static void method2(StringBuilder sBuilder){
        sBuilder.append("a");
        sBuilder.append("b");
        //...
    }
    //s1的操作:是線程不安全的
    public static StringBuilder method3(){
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
        return s1;
    }
    //s1的操作:是線程安全的
    // s1.toString() 裡面new String(),這個是線程不安全的,但是s1是線程安全的
    public static String method4(){
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
        return s1.toString();
    }
 
    public static void main(String[] args) {
        StringBuilder s = new StringBuilder();
        new Thread(new Runnable() {
            @Override
            public void run() {
                s.append("a");
                s.append("b");
            }
        }).start();
 
        method2(s);
    }
}
           

6、運作時資料區,哪些部分存在Error和GC(垃圾回收)?

知識點---JVM---虛拟機棧虛拟機棧概述虛拟機棧的存儲機關虛拟機棧的内部結構相關問題