執行時資料區域
我們這節關注中間灰色部分,注意綠色部分執行緒共享,黃色部分執行緒私有程式計數器
一塊較小的記憶體,是當前執行緒(執行緒私有)執行的位元組碼的行號指示器。
- 如果執行的是Java方法,計數器記錄的是正在執行的虛擬機器位元組碼指令的地址;如果是Native(本地方法),計數器值為空(Undefined)
- 唯一沒有
OutOfMemoryError
的區域
Java虛擬機器棧
虛擬機器棧是描述Java方法執行的記憶體模型
每個方法呼叫至完成,對應一個棧幀在虛擬機器棧中入棧到出棧的過程。區域性變數表:
- 存放基本資料型別、物件引用、returnAddress
- 區域性變數表所需的記憶體空間在編譯期完成,該空間是確定的,方法執行期間不改變。
兩種異常:
StackOverflowError
: 請求的棧深度超過允許範圍OutOfMemoryError
: 需要的記憶體超過允許範圍
本地方法棧
本地方法棧是描述本地方法執行的記憶體模型。它和Java虛擬機器棧很類似,區別就是它是為本地方法服務的。
Java堆
存放物件示例,也稱作(GC堆),是垃圾回收器管理的主要區域。
- 細分 新生代、老生代;Eden空間、From Survivor空間、To Survivor空間等
- 執行緒共享的堆裡可能劃分出私有的分配緩衝區(TLAB)。
方法區
儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯後的程式碼等資料。
執行時常量池 : 存放編譯器生成的各種字面常量和符號引用。
例子:String類在常量池的資料結構類似於HashSet,是唯一的。
String s1 = "abc";
String s2 = "abc"; // 存放在方法區的常量池(位元組碼常量)唯一
System.out.println(s1 == s2); // true
String s3 = new String("abc"); // 用了new,所以在堆中建立
System.out.println(s1 == s3); // false
System.out.println(s1 == s3.intern()); // true
複製程式碼
注意哦jdk1.8 String常量池搬到了堆中。如果想對intern()
瞭解更多,可以看我的這篇部落格。
HotSpot物件揭祕
物件建立
物件建立簡單描述:
new -> 根據常量池中符號看是否需要載入 -> 類載入 -> 分配記憶體 -> 初始化 ->構造方法
給物件分配記憶體的兩種方法:
- 指標碰撞
- 空閒列表
解決建立物件時執行緒安全問題兩種方法:
- 分配記憶體動作進行同步處理
- TLAB(共享堆中按執行緒劃分的執行緒私有部分)上分配,它分配完,再同步鎖定
物件的記憶體佈局
3塊區域:
-
物件頭
- 自身執行時的資料(MarkWord):HashCode、GC分代年齡、鎖狀態標誌、執行緒持有鎖、偏向執行緒ID、偏向時間戳等
- 型別指標:物件指向它的類後設資料的指標,虛擬機器可以根據它來確定該物件是哪個類的例項。
注意如果物件是陣列,那麼物件頭中還有一塊用於記錄陣列長度的資料。
-
例項資料
-
對齊填充 :當例項部分沒對齊時,通過對齊填充來補全
物件的訪問定位
- 控制程式碼訪問(2級指標)
- 直接指標