一文詳解JVM內存結構

JVM 內存結構

頂尖架構師棧

Java 虛擬機的內存空間分為 5 個部分:

  • 程序計數器
  • Java 虛擬機棧
  • 本地方法棧
  • 方法區

JDK 1.8 同 JDK 1.7 比,最大的差別就是:元數據區取代瞭永久代。元空間的本質和永久代類似,都是對 JVM 規范中方法區的實現。不過元空間與永久代之間最大的區別在於:元數據空間並不在虛擬機中,而是使用本地內存。

程序計數器(PC 寄存器)

  • 程序計數器的定義

程序計數器是一塊較小的內存空間,是當前線程正在執行的那條字節碼指令的地址。若當前線程正在執行的是一個本地方法,那麼此時程序計數器為 Undefined。

  • 程序計數器的作用

字節碼解釋器通過改變程序計數器來依次讀取指令,從而實現代碼的流程控制。

在多線程情況下,程序計數器記錄的是當前線程執行的位置,從而當線程切換回來時,就知道上次線程執行到哪瞭。

  • 程序計數器的特點

是一塊較小的內存空間。

線程私有,每條線程都有自己的程序計數器。

生命周期:隨著線程的創建而創建,隨著線程的結束而銷毀。

是唯一一個不會出現 OutOfMemoryError 的內存區域。

Java 虛擬機棧(Java 棧)

  • Java 虛擬機棧的定義

Java 虛擬機棧是描述 Java 方法運行過程的內存模型。

Java 虛擬機棧會為每一個即將運行的 Java 方法創建一塊叫做“棧幀”的區域,用於存放該方法運行過程中的一些信息,如:

  1. 局部變量表
  2. 操作數棧
  3. 動態鏈接
  4. 方法出口信息
  5. ……
  • 壓棧出棧過程

當方法運行過程中需要創建局部變量時,就將局部變量的值存入棧幀中的局部變量表中。

Java 虛擬機棧的棧頂的棧幀是當前正在執行的活動棧,也就是當前正在執行的方法,PC 寄存器也會指向這個地址。隻有這個活動的棧幀的本地變量可以被操作數棧使用,當在這個棧幀中調用另一個方法,與之對應的棧幀又會被創建,新創建的棧幀壓入棧頂,變為當前的活動棧幀。

方法結束後,當前棧幀被移出,棧幀的返回值變成新的活動棧幀中操作數棧的一個操作數。如果沒有返回值,那麼新的活動棧幀中操作數棧的操作數沒有變化。


由於 Java 虛擬機棧是與線程對應的,數據不是線程共享的(也就是線程私有的),因此不用關心數據一致性問題,也不會存在同步鎖的問題。

  • 局部變量表

定義為一個數字數組,主要用於存儲方法參數、定義在方法體內部的局部變量,數據類型包括各類基本數據類型,對象引用,以及 return address 類型。

局部變量表容量大小是在編譯期確定下來的。最基本的存儲單元是 slot,32 位占用一個 slot,64 位類型(long 和 double)占用兩個 slot。

對於 slot 的理解:

JVM 虛擬機會為局部變量表中的每個 slot 都分配一個訪問索引,通過這個索引即可成功訪問到局部變量表中指定的局部變量值。

如果當前幀是由構造方法或者實例方法創建的,那麼該對象引用 this,會存放在 index 為 0 的 slot 處,其餘的參數表順序繼續排列。

棧幀中的局部變量表中的槽位是可以重復的,如果一個局部變量過瞭其作用域,那麼其作用域之後申明的新的局部變量就有可能會復用過期局部變量的槽位,從而達到節省資源的目的。

赞(0)