JVM 執行時資料區詳解

阿豪聊乾貨發表於2017-03-05

一、執行時資料區

  Java虛擬機器在執行Java程式的過程中會把它所管理的記憶體劃分為若干個不同資料區域。

    1.有一些是隨虛擬機器的啟動而建立,隨虛擬機器的退出而銷燬,所有的執行緒共享這些資料區。

    2.第二種則是與執行緒一一對應,隨執行緒的開始和結束而建立和銷燬,執行緒之間相互隔離。

  Java虛擬機器所管理的記憶體將會包括以下幾個執行時資料區域

    

二、資料區詳解

1.程式計數器(Program Counter Register)

  • 也叫PC暫存器是一塊較小的記憶體空間,它的作用是儲存當前執行緒所執行的位元組碼的訊號指示器。
  • 每一條JVM執行緒都有自己的PC暫存器。
  • 在任意時刻,一條JVM執行緒只會執行一個方法的程式碼。該方法稱為該執行緒的當前方法(Current Method)。
  • 如果該方法是java方法,那PC暫存器儲存JVM正在執行的位元組碼指令的地址。
  • 如果該方法是native,那PC暫存器的值是undefined。
  • 此記憶體區域是唯一一個在Java虛擬機器規範中沒有規定任何OutOfMemoryError情況的區域。

2.Java虛擬機器棧(Java Virtual Machine Stack)

  • 每一個JVM執行緒都有自己的java虛擬機器棧,這個棧與執行緒同時建立,它的生命週期與執行緒相同。
  • 用於儲存區域性變數、操作棧、動態連結、方法出口
  • 虛擬機器棧描述的是Java方法執行的記憶體模型:
    • 每個方法被執行的時候都會同時建立一個棧幀(Stack Frame)用於儲存區域性變數表、運算元棧、動態連結、方法出口等資訊。
    • 每一個方法被呼叫直至執行完成的過程就對應著一個棧幀在虛擬機器棧中從入棧到出棧的過程。
    • 區域性變數表存放了編譯器剋制的各種基本資料型別(boolean、byte、char、short、int、float、long、double)、物件引用(Object reference)和位元組碼指令地址(returnAddress型別)。
  • JVM stack 可以被實現成固定大小,也可以根據計算動態擴充套件。
    • 如果採用固定大小的JVM stack設計,那麼每條執行緒的JVM Stack容量應該線上程建立時獨立地選定。
    • JVM實現應該提供調節JVM Stack初始容量的手段。
    • 如果採用動態擴充套件和收縮的JVM Stack方式,應該提供調節最大、最小容量的手段。
  • 對於32位的jvm,預設大小為256kb, 而64位的jvm, 預設大小為512kb,可以通過-Xss設定虛擬機器棧的最大值。不過如果設定過大,會影響到可建立的執行緒數量。
  • JVM Stack 異常情況:
    • StackOverflowError:當執行緒請求分配的棧容量超過JVM允許的最大容量時丟擲.
    • OutOfMemoryError:如果JVM Stack可以動態擴充套件,但是在嘗試擴充套件時無法申請到足夠的記憶體去完成擴充套件,或者在建立新的執行緒時沒有足夠的記憶體去建立對應的虛擬機器棧時丟擲。

3.本地方法棧(Native Method Stack)

  • Java虛擬機器可能會使用到傳統的棧來支援native方法(使用Java語言以外的其它語言編寫的方法)的執行,這個棧就是本地方法棧.
    • 如果JVM不支援native方法,也不依賴與傳統方法棧的話,可以無需支援本地方法棧。
    • 如果支援本地方法棧,則這個棧一般會線上程建立的時候按執行緒分配。
  • 異常情況:
    • StackOverflowError:如果執行緒請求分配的棧容量超過本地方法棧允許的最大容量時丟擲.
    • OutOfMemoryError:如果本地方法棧可以動態擴充套件,並且擴充套件的動作已經嘗試過,但是目前無法申請到足夠的記憶體去完成擴充套件,或者在建立新的執行緒時沒有足夠的記憶體去建立對應的本地方法棧,那Java虛擬機器將會丟擲一個OutOfMemoryError異常。

注:以上三個資料區屬於各個執行緒單享的,每個執行緒建立時都會建立此三個資料區。各個執行緒之間相互隔離,互不影響。

4.方法區(Method Area)

  • 方法區是可供各條執行緒共享的執行時記憶體區域。儲存了每一個類的結構資訊,例如:執行時常量池(Runtime Constant Pool)、欄位和方法資料、建構函式和普通方法的位元組碼內容、還包括一些在類、例項、介面初始化時用到的特殊方法。
  • 方法區在虛擬機器啟動的時候建立。
  • 方法區的容量可以是固定大小的,也可以隨著程式執行的需求動態擴充套件,並在不需要過多空間時自動收縮。
  • 方法區在實際記憶體空間中可以是不連續的。
  • Java虛擬機器實現應當提供給程式設計師或者終端使用者調節方法區初始容量的手段,對於可以動態擴充套件和收縮方法區來說,則應當提供調節其最大、最小容量的手段。
  • Java 方法區異常:
    • OutOfMemoryError: 如果方法區的記憶體空間不能滿足記憶體分配請求,那Java虛擬機器將丟擲一個OutOfMemoryError異常。

執行時常量池(Runtime Constant Pool

  • 執行時常量池是每一個類或介面的常量池(Constant_Pool)的執行時表現形式,它包括了若干種常量:編譯器可知的數值字面量到必須執行期解析後才能獲得的方法或欄位的引用。
  • 執行時常量池是方法區的一部分。每一個執行時常量池都分配在JVM的方法區中,在類和介面被載入到JVM後,對應的執行時常量池就被建立。
  • 在建立類和介面的執行時常量池時,可能會遇到的異常:
    • OutOfMemoryError:建立類和介面時,若構造執行時常量池所需的記憶體空間超過了方法區所能提供的最大記憶體空間後時丟擲.

5.Java堆(Heap)

  • 在JVM中,堆是可供各條執行緒共享的執行時記憶體區域,也是供所有類例項和資料物件分配記憶體的區域。
  • Java堆是Java虛擬機器所管理的記憶體中最大的一塊。
  • 通過-Xms和-Xmx來控制初始堆大小和最大堆大小
  • Java堆載虛擬機器啟動的時候就被建立,堆中儲存了各種物件,這些物件被自動管理記憶體系統(Automatic Storage Management System,也即是常說的“Garbage Collector(垃圾回收器)”)所管理。這些物件無需、也無法顯示地被銷燬。
  • Java堆的容量可以是固定大小,也可以隨著需求動態擴充套件,並在不需要過多空間時自動收縮。
  • Java堆所使用的記憶體不需要保證是物理連續的,只要邏輯上是連續的即可。
  • JVM實現應當提供給程式設計師調節Java 堆初始容量的手段,對於可動態擴充套件和收縮的堆來說,則應當提供調節其最大和最小容量的手段。
  • Java 堆異常:
    • OutOfMemoryError:如果實際所需的堆超過了自動記憶體管理系統能提供的最大容量時丟擲。

參考原文:http://chenzhou123520.iteye.com/blog/1585224

     http://www.open-open.com/lib/view/open1383745340321.html

相關文章