1. 程式人生 > 其它 >jvm讀書記錄1-Java虛擬機器執行時資料區域

jvm讀書記錄1-Java虛擬機器執行時資料區域

Java虛擬機器執行時的記憶體資料區域可分為:

  1. 方法區
  2. 虛擬機器棧
  3. 本地方法棧
  4. 程式計數器

其中堆和方法區由執行緒共享;虛擬機器棧、本地方法區、程式計數器執行緒隔離的,即每個執行緒都有。

下面簡單描述下上述的各個分割槽的職責和功能

一、程式計數器

程式計數器是一塊較小的記憶體空間,在java虛擬機器的概念模型裡面,位元組碼直譯器工作時,通過改變這個計數器來選去下一個要執行的位元組碼指令,他是程式控制流的指示器;包括:分支、迴圈、異常處理、執行緒恢復。

java虛擬機器的多執行緒時通過執行緒輪流切換、分配處理器執行時間的方式來實現的。因此,為了執行緒切斷後能恢復到正確的執行位置,每天執行緒都需要一個獨立的程式計數器。

二、Java虛擬機器棧

Java虛擬機器棧時執行緒私有的,他的生命週期與執行緒相同。

虛擬機器棧描述的是java方法執行的執行緒記憶體模型:

每個方法被執行的時候,Java虛擬機器都會同步建立一個棧幀,用於儲存區域性變量表、運算元棧、動態連線、方法出口等資訊。每一個方法被呼叫直至執行完畢的過程,就對應著一個棧幀在虛擬機器中從入棧道出棧的過程。

區域性變量表

區域性變量表存放了編譯器可知的各種java虛擬機器基本資料型別(boolean、byte、char、short、int、float、long、double)、物件引用(reference型別,他並不等同於物件本身,可能是一個指向物件其實地址的引用指標,也可能是指向一個代表物件的控制代碼會在與此物件相關的位置)。

這些資料型別在區域性變量表中的儲存空間以區域性變數槽來表示,區域性變量表在記憶體空間編譯期間完成分配,當進入一個方法時,這個方法需要在棧幀中分配多大的空間時完全確定的,在方法執行期間不會改變大小。這裡的大小指的是變數槽的資料,實際大小和虛擬機器真正使用多大的空間有關係;例如一個變數槽佔用多少bit。

在這個記憶體區域有兩類異常

  • StackOverflowError:執行緒請求的棧深度大於虛擬機器所允許的深度
  • outofmemoryerror:java虛擬機器棧容量可以動態擴充套件,當棧擴充套件時無法申請到足夠的記憶體

HotSpot虛擬機器的棧容量時不可擴充套件的,classic可以。所以在hotspot虛擬機器上時不會出現oom異常的,只要執行緒申請棧空間成功就不會oom(會StackOverflowError),如果申請失敗則會時oom;

三、本地方法棧

本地方法棧和虛擬機器棧發揮的作用非常相似,區別就是虛擬機器棧位虛擬機器執行java方法服務,而本地方法方法棧則為虛擬機器使用到的本地方法服務。本地方法棧也會丟擲StackOverflowError和oom異常。

四、Java 堆

Java堆事所有執行緒共享的一塊記憶體區域,在虛擬機器啟動時建立。此記憶體區域的唯一目的就是存放物件例項,Java世界裡面“幾乎”所有的物件例項都在這裡分配記憶體。

Java堆事垃圾收集器管理的記憶體區域,從記憶體回收的角度看,現代垃圾收集器大部分都是基於分代收集理論設計的(例如:新生代、老年代;eden空間、from survivor空間、tosurvivor空間),但是也有不分代設計的垃圾收集器。

如果從分配記憶體的角度看,所有的執行緒共享的java堆中可以劃分出多個執行緒私有的分配緩衝區(TLAB),以提升物件分配時的效率。

五、方法區

方法區與堆一樣,是各個執行緒共享的記憶體區域,它用於儲存已被虛擬機器載入的型別資訊、常量、靜態變數、即時編譯器編譯後的程式碼快取等資料。

方法區與永久代

在hotspot虛擬機器上,有的人把方法區稱呼為永久代。這個其實是因為當時hotspot虛擬機器當時選擇把收集器的分代設計擴充套件至方法區,好省掉為方法區單獨編寫垃圾收集的工作。到了jdk 7 的hotspot已經把原本放在永久代的字串常量池、靜態變數移出,到了jdk8 已經完全廢棄了永久代。

方法區的垃圾收集目標主要是針對常量池的回收和型別的解除安裝,方法區也會出現oom的異常。

六、直接記憶體(堆外記憶體)

直接記憶體並不是虛擬機器執行時資料區的一部分。

參考:

《深入理解Java虛擬機器》周志明