HotSpot虛擬機對象的創建

                   注意:此處對象的創建過程僅適用於普通的Java對象,不包括數組和Class對象

對象的創建過程

  1. 虛擬機遇到一條new指令時,首先將去檢查這個指令的參數是否能在常量池中定位到一個類的符號引用(類的權限定類名??),並且檢查這個符號引用代表的類是否已被加載、解析和初始化過。如果沒有,那必須先執行相應的類加載過程。
  2. 在類加載檢查通過後,接下來虛擬機將爲新生對象分配內存。對象所需內存的大小在類加載完成後便可完全確定。有兩種內存分配方式:指針碰撞(Bump the Pointer)和空閒列表(Free List),選擇哪種分配方式由Java堆是否規整決定,而Java堆是否規整又由所採用的垃圾收集器是否帶有壓縮整理功能決定。
  3. 內存分配完成後,虛擬機需要將分配到的內存空間都初始化爲零值(不包括對象頭),如果使用TLAB,這一工作過程也可以提前至TLAB分配時進行。這一步操作保證了對象的實例字段在Java代碼中可以不賦初始值直接使用時,程序能訪問到這些字段的數據類型所對應的零值。
  4. 虛擬機要對對象頭這是:對象的哈希碼、對象的GC分代年齡、方法區對象類型數據的指針和是否啓用偏向鎖的設置。
  5. 經過以上操作,從虛擬機的角度來看,一個新的對象已經產生了。一般來說(由字節碼中是否跟隨invokespecial指令所決定),執行new指令之後會接着執行<init>方法,這樣對象纔算完全產生出來。

對象內存佈局

  1. 在HotSpot虛擬機中,對象在內存中存儲的佈局可以分爲3塊區域:對象頭、實例數據(Instance Data)和對齊填充(Padding)。
  2. HostSpot虛擬機的對象頭包括兩部分:第一部分用於存儲對象自身的運行時數據,如哈希碼(HashCode)、GC分代年齡、鎖狀態標誌、線程持有的鎖、偏向線程ID、偏向時間戳等。稱之爲Mark Word。第二部分是類型指針,即對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。如果對象是一個Java數組,在對象頭中還必須有一塊用於記錄數組長度的數據。
  3. 實例數據部分是對象真正存儲的有效信息,即在程序代碼中所定義的各種類型的字段內容。無論是從父類繼承下來的,還是子類中定義的,都需要記錄起來。存儲順序會受到虛擬機分配策略參數(FieldsAllocationStyle)和字段在java源碼中定義順序的影響。HotSpot虛擬機默認的分配策略爲longs/doubles、ints、shorts/chars、bytes/booleans、oops(Ordinary Object Pointer),從分配策略中可以看出,相同寬度的字段總是被分配到一起。在滿足這個前提條件下,在父類中定義的變量會出現在子類之前。如果CompactFields參數值爲true(默認爲true),那麼子類之中較窄的變量也可能會插入到父類變量的空隙之中。
  4. 第三部分對齊填充,由於HotSpot VM的自動內存管理系統要求對象起始地址必須是8字節的整數倍,即對象的大小必須是8字節的整數倍。

對象的訪問定位

Java程序需要通過棧上的Reference數據來操作堆上的具體對象。
  1. 使用句柄
    Java堆中將會劃分出一塊內存來作爲句柄池,reference中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據與類型數據各自的具體地址信息。
  2. 直接指針訪問
    Java堆對象的佈局中就必須考慮如何放置訪問類型數據的相關信息,而reference中存儲的直接就是對象地址。

    HotSpot虛擬機使用的是直接指針訪問,查詢速度快。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章