Java8虛擬機內存模型

1.Java虛擬機運行時數據區

在JDK1.8之前,JVM運行時數據區分爲堆、虛擬機棧、本地方法棧、方法區、程序計數器。如下圖所示:

虛擬機棧:線程私有,隨線程創建而創建。棧裏面是一個一個“棧幀”,每個棧幀對應一次方法調用。棧幀中存放了局部變量表(基本數據類型變量和對象引用)、操作數棧、方法出口等信息。當棧調用深度大於JVM所允許的範圍,會拋出StackOverflowError的錯誤。

本地方法棧:線程私有,這部分主要與虛擬機用到的Native方法相關,一般情況下,並不需要關心這部分的內容。

程序計數器:也叫PC寄存器,JVM支持多個線程同時運行,每個線程都有自己的程序計數器。倘若當前執行的是 JVM 的方法,則該寄存器中保存當前執行指令的地址;倘若執行的是native方法,則PC寄存器中爲空。(PS:線程執行過程中並不都是一口氣執行完,有可能在一個CPU時鐘週期內沒有執行完,由於時間片用完了,所以不得不暫停執行,當下一次獲得CPU資源時,通過程序計數器就知道該從什麼地方開始執行)

方法區:方法區存放類的信息(包括類的字節碼,類的結構)、常量、靜態變量等。字符串常量池就是在方法區中。雖然Java虛擬機規範把方法區描述爲堆的一個邏輯部分,但是它卻有一個別名叫做Non-Heap(非堆),目的是與Java堆區分開來。很多人都更願意把方法區稱爲“永久代”(Permanent Generation)。從jdk1.7已經開始準備“去永久代”的規劃,jdk1.7的HotSpot中,已經把原本放在方法區中的靜態變量、字符串常量池等移到堆內存中。

堆:堆中存放的是數組(PS:數組也是對象)和對象。當申請不到空間時會拋出OutOfMemoryError。
2.PermGen(永久代)

“方法區”是JVM的規範,而“永久代”是方法區的一種實現,並且只有HotSpot纔有“PermGen space”,而對於其他類型的虛擬機並沒有“PermGen space”。

在JDK1.8中,HotSpot已經沒有“PermGen space”這個區間了,取而代之是Metaspace(元空間)
3.Metaspace(元空間)

在JDK1.8中,永久代已經不存在,存儲的類信息、編譯後的代碼數據等已經移動到了MetaSpace(元空間)中,元空間並沒有處於堆內存上,而是直接佔用的本地內存(NativeMemory)。

元空間的本質和永久代類似,都是對JVM規範中方法區的實現。

不過元空間與永久代之間最大的區別在於:元空間並不在虛擬機中,而是使用本地內存。

元空間的大小僅受本地內存限制,可以通過以下參數來指定元空間大小:

-XX:MetaspaceSize,初始空間大小,達到該值就會觸發垃圾收集進行類型卸載,同時GC會對該值進行調整:如果釋放了大量的空間,就適當降低該值;如果釋放了很少的空間,那麼在不超過MaxMetaspaceSize時,適當提高該值
-XX:MaxMetaspaceSize,最大空間,默認是沒有限制的
-XX:MinMetaspaceFreeRatio,在GC之後,最小的Metaspace剩餘空間容量的百分比,減少爲分配空間所導致的垃圾收集
-XX:MaxMetaspaceFreeRatio,在GC之後,最大的Metaspace剩餘空間容量的百分比,減少爲釋放空間所導致的垃圾收集
4.堆內存劃分

在JDK1.7以及其前期的JDK版本中,堆內存通常被分爲三塊區域:Young Generation、Old Generation、Permanent Generation for VM Matedata

在JDK1.8中把存放元數據中的永久內存從堆內存中移到了本地內存中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章