本文介紹的對象創建過程僅限於普通Java對象,不包括數組和Class對象。
1.類加載檢查
虛擬機遇到一條new指令時,首先去檢查該指令的參數能否在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已被加載、解析和初始化過。
2.為新生對象分配內存
對象所需內存的大小在類加載完成后便可以完全確定,為對象分配空間的任務等同於把一塊確定大小的內存從Java堆中划分出來。划分的方法主要有兩種:
a、指針碰撞
如果java堆中內存是絕對規整的,所有用過的內存都放在一邊,未使用的內存放在另一邊,中間放着一個指針作為分界點的指示器,那所分配內存就僅僅是把那個
指針指向空閑空間那邊挪動一段與對象大小相等的距離。
b、空閑列表
如果java堆中的內存並不是規整的,已使用的內存和未使用的內存相互交錯,就無法使用指針碰撞了,虛擬機必須維護一個列表來記錄哪些內存是可用的,在分配的時候
從列表中找到一塊足夠大的空間划分給對象實例並更新表上的記錄。
3.后續工作
內存分配完成后,虛擬機需要將分配到的內存空間初始化為零值(不包括對象頭),然后對對象進行必要的設置(主要是對象頭信息的設置)。
此時,在虛擬機看來一個新的對象已經產生了,但是從程序員的角度來看,對象創建才剛剛開始,需要執行<init>方法,把對象按照程序員的意願進行初始化。
附錄
對象在虛擬機中存儲的布局可以分為3塊區域:對象頭、實例數據和對齊填充。
對象頭包含兩部分信息:第一部分用於存儲對象自身的運行時數據(如哈希碼、GC分代年齡、鎖狀態標志、線程持有的鎖、偏向線程ID以及偏向時間戳等)。
另一部分是類型指針,即對象指向它的類元數據的指針,如果對象是一個Java數組,對象頭中還必須有一塊用於記錄數組長度的數據。
實例數據部分是對象真正存儲的有效信息,也就是程序代碼中所定義的各種類型的字段內容。
對齊填充並不是必然存在的,僅僅起着占位符的作用,因為HotSpot VM的自動內存管理系統要求對象起始地址必須是8字節的整數倍。