1. 程式人生 > >深入理解JVM(一)——物件的建立

深入理解JVM(一)——物件的建立

物件的建立

物件的建立,在語言層面上,通常只是new這個關鍵字而已。(本章所討論的物件限於普通Java物件,不包括陣列和 Class物件)虛擬機器遇到new指令時:

  1. 檢查這個指令的引數是否能在常量池定位到一個類的符號引用。
  2. 檢查這個符號引用代表的類是否已被載入,解析,初始化過。
  3. 如果沒有必須執行相應的類載入過程

類載入檢查後,虛擬機器會為新生物件分配記憶體。物件所需的記憶體在類載入時可完全確定,為物件分配空間等同於把一塊確定大小的記憶體從Java堆中拿出來。

規整的記憶體空間可用指標碰撞法分配
非規整的記憶體空間用空閒列表法分配(虛擬機器維護一張列表記錄哪些記憶體塊是可用的)

記憶體分配在併發情況下的執行緒安全

  1. 對分配記憶體空間的動作進行同步處理——實際上虛擬機器採用的CAS配上失敗重試的方式保證更新操作的原子性
  2. 把記憶體分配的動作按照執行緒劃分在不同的空間上進行,即每個執行緒在Java堆上預先分配一小塊記憶體(Thread Local Allocation Buffer,TLAB),虛擬機器是否啟動TLAB由引數-XX:+/-UserTLAB設定

記憶體分配完成,虛擬機器將分配到的記憶體空間初始化為零值(不包括物件頭)

虛擬機器對物件進行必要的設定

  • 這個物件是哪個類的例項
  • 如何才能找到類的元資料資訊
  • 物件的雜湊碼
  • 物件的GC分代年齡等資訊

這些資訊存放在物件的物件頭中

執行init方法
物件空間分配完成,但是所有的欄位都是零。一般來說由位元組碼中是否跟隨invokespecial指令決定,執行玩new指定後,是否執行init方法

物件的記憶體佈局

包括3個區域,物件頭,例項資料,對齊填充

  • 物件頭

    儲存自身執行時的資料,如雜湊碼,GC分代年齡,鎖狀態標誌,執行緒持有的鎖,偏向執行緒ID,偏向時間戳等,長度為32bit/64bit,根據虛擬機器的位數決定。官方成為Mark Word,被設計為一個非固定的資料結構,以便在極小的空間儲存更多的資訊。
    儲存型別指標,即指向他的類元資料(確定該物件是哪個類的例項),陣列還需要記錄長度

  • 資料例項

    物件真正儲存的有效資訊,程式程式碼定義的各種欄位內容,包括父類繼承的。這部分的儲存順序會受到虛擬機器的分配策略引數和欄位定義順序影響。

  • 對齊填充

    不是必然存在,僅僅是佔位符的作用。HotSpot VM記憶體管理系統要求物件的起始地址必須是8位元組的整數倍,所以物件也必須是8位元組的整數倍。

物件的訪問定位

建立物件是為了使用物件,Java程式需要通過棧上的reference資料來操作堆上的具體物件。
Java虛擬機器並未規定具體的定位方式,主流的訪問方式有兩種

  • 使用控制代碼

Java劃分一塊記憶體作為控制代碼池,reference中存的是物件的控制代碼地址,控制代碼中包含物件的例項資料與型別資料各自具體的地址。(GC時物件被移動,reference不需要修改)

  • 直接指標

Java堆物件的佈局必須考慮如何放置訪問型別資料的相關資訊,而reference中儲存的就是物件的地址。(速度快,節省一次指標定位的開銷)(HotSpot VM)