1. 程式人生 > >讀薄《深入理解 JAVA 虛擬機器》Java記憶體區域

讀薄《深入理解 JAVA 虛擬機器》Java記憶體區域

很早之前看了《深入理解 JAVA 虛擬機器》並寫下了讀書筆記。最近在結合一些其他資料整理部落格。希望能幫助到其他人抓住書的重點。
Java執行時資料區域

Java執行時資料區域

白色為執行緒獨佔的,灰色為執行緒共享的。

Java在執行的時候會把他所管理的記憶體劃分為若干區域,經常有人把記憶體區域分為堆記憶體和棧記憶體,這種記憶體分發比較粗糙,下面我們來仔細介紹一下 Java 中的記憶體區域。

程式計數器

程式記錄器是用於記錄程式所執行到的位置的,程式工作的時候就是通過改變這個計數器的值來選擇下一條需要執行的指令(類似計算機組成原理中的 PC 計數器)。

如果執行緒正在執行一個 Java 方法,則計數器記錄了正在執行的指令的地址。如果在執行一個 Native 方法,則這個暫存器計數值為空,注意這是唯一一個沒有規定任何OutOfMemoryError

的區域。

Java虛擬機器棧

每一條執行緒都要有獨立的 Java 虛擬機器棧每一個方法的執行都會建立一個棧幀,方法執行結束以後棧幀就會被彈出,這個棧幀儲存了區域性變量表,運算元棧,動態連結,方法出口。可以類比於在組合語言中轉跳到一個方法時需要用pushad來儲存暫存器中的值,而這一串儲存在暫存器中的值就是一個棧幀。

區域性變量表

區域性變量表是棧幀的一部分,裡面存放了各種基本資料型別和物件引用。,因為除了long和double會佔用兩個區域性變數空間,其他的都是佔用一個區域性變數空間,所以每個方法需要分配多少區域性變數空間是確定的,而且是在編譯的時候確定的。

在Java虛擬機器中,如果執行緒請求的棧深度大於虛擬機器所允許的深度,則會丟出StackOverflowError

本地方法棧

與 Java 虛擬機器棧的區別就是它是為 native 方法服務的。有些虛擬機器會將他們合二為一。

Java堆

new 出來的物件儲存區域,GC 主要發生在這個記憶體區域上。

方法區

也被稱為永久代。 用於儲存虛擬機器載入的類資訊,常量,靜態變數,即時編譯以後的程式碼。方法區裡對於物件的回收的對型別的解除安裝條件非常苛刻,回收效益不大,但是還是有必要回收的。

執行時常量池

方法區的一部分,存放編譯器生成的各種字面量(1,2,“abstract”)和符號引用。

一般來說除了符號引用,直接引用也會儲存在這個地方。

執行常量池相對於Class檔案常量池另外一個重要的區別就是具備動態性,Java 執行中可能動態產生常量,比如String 類的 intern()

方法。

物件的建立

建立物件分為這幾部

  1. 首先去檢查這個類有沒有被載入過,如果沒有則載入該類。
  2. 在載入完類後,物件分配記憶體,記憶體大小在類載入完成後已經可以確定。
  3. 記憶體分配完成後將分配到的記憶體空間置為 0,這一步保證物件例項欄位可以不用賦值直接使用
  4. 填充物件頭

物件的記憶體佈局

物件在記憶體區域中

[ [ mark word, 型別指標 ],例項資料,對齊填充 ]

物件頭

物件頭由 mark word 和型別指標組成,為了虛擬機器的效率,Mark Word 會根據物件的狀態複用儲存空間。通過標誌位來表示當前儲存的是什麼。

例項資料

例項資料部分儲存物件有效資訊,HotSpot虛擬機器預設分配策略為

long/double,int,short/char,byte,boolean。