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中把存放元數據中的永久內存從堆內存中移到了本地內存中,JDK1.8中JVM堆內存結構就變成了如下:
5. 堆統計信息
6. 其它相關
7. 參考
https://blog.csdn.net/qq_31337311/article/details/78799262
https://www.cnblogs.com/paddix/p/5309550.html
https://blog.csdn.net/zwrlj527/article/details/79399715