1.Java運行時數據區
- 方法區,堆線程共享。虛擬機棧,本地方法棧和程序計數器線程私有。
2.程序計數器(PC計數器)
- 占用較小的一塊內存空間,當執行Java方法時記錄正在執行的虛擬機字節碼指令地址,如果執行Native方法則計時器值為空。
3.Java虛擬機棧
- java方法執行時的內存模型
- 查看Java虛擬機棧詳細
3.1 棧幀
- 每個方法都會在虛擬機棧中創建一個對應的棧幀,用於存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。
- 一個方法的調用到結束就對應這一個棧幀從虛擬機棧入棧到出棧。
4.棧內存和堆內存
- 一般我們說的棧內存和堆內存的棧就指虛擬機棧內存或者就指局部變量表,堆就是堆內存。最關心的也就是這兩塊。
5.本地方法棧
- 本地方法棧和虛擬機棧作用相似,虛擬機棧為虛擬機執行java方法(字節碼)服務,本地方法棧為jvm使用Native方法服務。
- 本地方法 關鍵字 native ,這些方法一般用來調用本地方法庫中的方法這些方法操作底層大多用C 實現。
- 有的虛擬機將本地方法棧和虛擬機棧合在一起,如HotSpot。
6.java堆
- 最大的一塊內存,存放對象實例的地方。
- Java堆是垃圾收集器管理的主要區域,也稱GC堆。
- Java堆物理上可不連續,邏輯上連續。
- 堆中沒有完成實例分配,並且對也無法在擴展時拋出 OutOfMemoryError異常
7.方法區
- 方法區是一種規范,1.8之前永久代是其一周種實現,1.8開始使用元空間代替永久代。
- 存已經被虛擬機加載的類信息(Class對象)、常量、靜態變量、即時編譯器JIT編譯過后的代碼數據。
- jdk 1.7、1.8 對方法區做出了修改,1.8 取消了永久代使用元空間代替。
- 方法區被Java虛擬機規范描述為堆的一個邏輯部分,但它不是堆,有一個別名叫非堆Non-Heap
- jdk1.6 及之前方法區位於永久代(PermGen),永久代和堆相互隔離。
- 永久代使用的是jvm內存,而元空間使用本地內存,隨意元空間可以存放更多信息。
- 方法區可以不需要連續的內存空間,也可以固定大小,也可以擴展,也可以不實現垃圾收集,如果實現則主要針對常量池的回收和類型的卸載。
7.4 運行時常量池
- 在方法區,用來存放編譯期生成的各種符號引用和字面量。
- 編譯期將各種符號引用和字面量放置在class文件的常量池中,解析后在運行時常量池,字符串在方法區的字符串常量池中(1.7之前),方法運行時復制到局部變量表中。1.7開始字符串常量池被移入堆中。
- 符號引用: String ss = "asdsfg" ss這個符號就是符號引用。解析階段解析為直接引用
- 字面量: 值本身 如 asdfg
- 常量池中有各種虛擬機正常運行需要的字符串,所以有些即使不創建也還會存在於字符串常量池中如"java"。
8.直接內存
- 並非虛擬機運行時的內存,也不再jvm規范中定義。
- 在JDK 1.4中新加入了NIO(New Input/Output)類,引入了一種基於通道(Channel)與緩沖區(Buffer)的I/O方式,它可以使用Native函數庫直接分配堆外內存,然后通過一個存儲在Java堆中的DirectByteBuffer對象作為這塊內存的引用進行操作。這樣能在一些場景中顯著提高性能,因為避免了在Java堆和Native堆中來回復制數據。
9.對象的創建
- 普通Java對象創建,不包括數組和Class對象。
- 類加載 連接 類加載檢查
- 檢查通過后為對象分配內存,對象內存大小在類加載時就已經確定了。
- 將分配的內存初始化為0值,這一步保證了實例字段即使不賦初值也可使用。
- 對對象進行設置,如對象哈希碼,是哪個類的實例,GC分代年齡。
- <init> 方法執行,對象執行初始化。
10.對象內存分布
- 對象在內存中分為3塊區域,對象頭(Header)、實例數據(Instance Data)、對齊填充(Padding)。
- 實例數據:包括從父類繼承下來的字段,並且將寬度相同的字段分配到一起。
- 對齊填充:HotSpot VM 的內存自動管理系統要求對象起始地址必須是8字節的整數倍,就是說對象大小必須是8字節整數倍,而對象頭正好是8字節的倍數,所以實例數據不夠8字節整數倍時會補齊填充。
10.1 對象頭
- 對象頭分為2部分,第一部分存儲對象自身運行時數據,第二部分存儲類型指針。
- 對象頭作用 查看博客
- 自身運行時數據(Mark Word):如哈希碼、GC分代年齡、鎖轉態標志、線程持有的鎖,偏向線程ID、偏向時間戳。Mark Word是非固定的數據結構,以便存儲更多信息,根據對象狀態不同各個信息所占位數會變化,但總體肯定是8字節倍數。
- 類型指針:指向元數據(Class類數據)的指針
- 如果對象是數組那么對象頭還有一塊用於記錄數組長度的區域,因為普通Java對象通過元數據可以確定大小,而數組的元數據無法確定數組大小。
11.對象定位
- 主流的訪問對象的方式有兩種,通過句柄訪問和直接訪問,HotSpot 采用直接訪問。
- 通過句柄訪問就是在堆中有一個句柄池存放對象實例數據與類型數據各自的具體地址,棧中的引用保存句柄的地址,好處是引用保存的地址不會變比較穩定,對象改變也只改變句柄池中的地址。
- 直接訪問就是引用直接指向對象,好處就是速度快。