Java記憶體區域學習

hatch發表於2018-04-12

執行時區域

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

Java記憶體區域學習

程式計數器

當前執行緒所執行的位元組碼的指示器。通過改變這個計數器的值來選取下一個需要執行的位元組碼指令,分支、迴圈、跳轉、異常、執行緒恢復等都需要這個計數器完成。

每個執行緒一個獨立的程式計數器,各執行緒之間互不影響,獨立儲存。

執行Java方法時:正在執行虛擬位元組碼的指令地址

執行Native方法:值為空(Undefined)
複製程式碼

唯一一個Java虛擬機器規範中沒有規定OutOfMemoryError的區域

虛擬機器棧

執行緒私有,生命週期和執行緒一致。

描述的是Java方法執行的記憶體模型:方法執行同時建立一個棧幀,方法從呼叫到執行完成,就是一個棧幀在虛擬機器棧中入棧到出棧的過程。

其中棧幀用於儲存:區域性變數表、運算元棧、動態連結、方法出口等資訊。

區域性變數表中存放了編譯期間可知的基本資料型別和物件引用。

64位的long和double型別的資料會佔2個區域性空間變數,其餘型別只佔1個。因區域性變數表中所需記憶體是在編譯期間完成的,所以這個方法在幀中需要分配多少區域性變數空間是確定的。

這部分割槽域異常:StackOverFlowError和OutOfMemoryError 、

本地方法棧

與虛擬機器棧的作用類似。本地方法棧是為Native方法服務。丟擲異常與虛擬機器棧一致。

堆是Java虛擬機器中記憶體最大的一塊。執行緒共享,虛擬機器啟動時建立。存放物件例項。

幾乎所有的物件都在這裡分配記憶體。【隨著JIT編譯器的發展和逃逸分析技術的成熟,棧上分配和標量替換,物件不一定在堆中分配】

堆是垃圾收集管理器的主要區域,也叫GC堆。細分為:新生代、老年代。eden->from survivor->to survivor

通過-Xmx和-Xms控制擴充套件,無法擴充套件時丟擲OutOfMemoryError異常

方法區

執行緒共享。儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯的程式碼。也叫非堆,也稱永久代。

-XX:MaxPermSize

記憶體回收目標:常量池的回收和類的解除安裝

OutOfMemoryError

執行時常量池

方法區的一部分

OutOfMemoryError

直接記憶體

不是虛擬機器執行時區的一部分。

JDK1.4新加入的NIO類,引入Channel和Buffer的I/O方式,使用Native函式庫直接分配堆外記憶體,使用DirectByteBuffer作為這塊記憶體的引用進行操作。

受本機記憶體大小和處理器定址空間的限制

OutOfMemoryError

虛擬機器中的物件

物件的建立

當遇到new指令時

首先檢查這個指令的引數是否能在常量池中定位到一個類的符號引用。【並檢查該符號引用代表的類是否已被載入、解析、初始化過,若沒有則執行類載入】

類載入通過之後,為新生物件分配記憶體

記憶體分配完成後,需將分配到的記憶體空間都初始化為零值,不包括物件頭

接下來,虛擬機器要對物件進行必要的設定,設定物件頭。如這個物件是那個類的例項。如何才能找到類的後設資料資訊、物件的雜湊碼、物件的GC分代年齡等資訊。
複製程式碼

分配記憶體方式:

指標碰撞

空閒列表
複製程式碼

當使用Serial、ParNew等帶compact過程的收集器時:分配演算法是指標碰撞

使用CMS基於Mark-Sweep演算法的收集器時:分配演算法採用空閒列表

分配物件記憶體空間併發下執行緒安全問題:

採用CAS加上失敗重試保證更新的原子性

把記憶體分配動作按執行緒劃分在不同的空間進行,即每個執行緒在Java堆中預先分配一塊小記憶體,成為本地執行緒分配緩衝區【TLAB】  -XX:+、-UseTLAB
複製程式碼

物件建立完成之後還有進行init,按照程式設計師的意願進行初始化。

物件記憶體佈局

物件記憶體佈局分為三塊

物件頭、例項資料、對齊填充
複製程式碼

物件頭

物件頭包含兩部分:

儲存物件自身的執行資料

型別指標
複製程式碼

物件自身的執行資料

包含雜湊碼、GC分代年齡、鎖狀態標誌、執行緒持有鎖、偏向執行緒ID、偏向時間戳等。也稱Mrak Word

型別指標

物件指向它的類後設資料的指標。虛擬機器通過這個指標來確定物件是屬於哪個類的例項

物件例項資料部分

物件真正儲存的有效資訊,各種型別的欄位內容。

對齊填充部分

不是必然存在的。起著佔位符的作用。

物件起始地址必須是8位元組的整數倍。當物件例項資料部分沒有對齊時,就需要對齊填充了。

物件的訪問定位

物件的訪問定位目前有兩種流行的方式:

使用控制程式碼

直接指標
複製程式碼

控制程式碼

Java記憶體區域學習

直接指標

Java記憶體區域學習

對比

使用控制程式碼好處:棧中引用儲存的是穩定的控制程式碼地址,物件被移動時只會改變控制程式碼中的例項資料指標,引用本身不需變化

使用直接引用好處:速度快,節省一次指標定位的時間開銷

相關文章