本文讨論的是Java對象在jvm中建立的過程(不包括數組、Class對象的建立)
-
類的加載、連接配接、初始化
在語言層面上,我們建立對象需要new關鍵詞來建立對象,當JVM遇到這個指令時,首先檢查這個指令能否在常量池中定位到這個類的符号引用,并且要檢查這個符号引用代表的類是否已經被加載、連接配接(驗證、準備、解析)、初始化過,如果沒有那麼就去執行類加載過程,詳見:類加載機制,這裡不再贅述。
-
新生對象配置設定記憶體的方式
2.1 對象記憶體布局
要配置設定新生對象記憶體,那麼先得知道它所需記憶體大小,在HotSpot虛拟機中,對象包含三個部分:對象頭、執行個體資料、對齊填充
對象頭:包含兩部分:一部分存儲哈希碼、GC分代年齡、鎖狀态标志、線程持有鎖、偏向線程ID等,在32位VM中對應32比特位(25位哈希碼,4位分代年齡,2位鎖标志,1位固定為0,至于其他資訊則會在鎖标志位等其他比特位可檢視出),64VM對應64比特。另一部分是類型指針,對象指向它的類型中繼資料指針,用來确定這個指針是哪個類的執行個體。
執行個體資料:包含其中所有有效資訊(各種類型字段内容),包括自己和父類繼承下來的字段
對齊填充:占位符的作用,無其他作用,(任何對象的大小都必須是8位元組的整數倍)
2.2 配置設定記憶體方式
假設Java堆記憶體是絕對規整的(無記憶體碎片,所有使用過的記憶體在一起,所有沒被使用過的記憶體在一起),中間臨界處有一個指針,配置設定對象時,僅僅把指針向空閑方向移動此對象大小相等的距離,這種配置設定方式稱為指針碰撞;
而如果記憶體不規整,那麼vm必須維護一個空閑記憶體清單,配置設定的時候找到一塊足夠大的空間配置設定給對象執行個體,并更新清單,這種配置設定方式成為空閑清單。是以選擇那種配置設定方式由垃圾收集器所決定(垃圾收集器采用的收集算法不同,所對應算法是否會産生記憶體碎片也不同,Serial,ParNew為指針碰撞,高效簡單,而CMS這種則是采用空閑清單較為複雜的方式)。
-
并發問題
建立對象是非常頻繁的行為,僅僅修改一個指針,在并發場景下也不是線程安全的(正在給對象A配置設定記憶體,還沒來得及修改指針,B就用了原來的指針來配置設定記憶體)。VM則采用CAS配上失敗重試的方式保證其原子性,或者采用TLAB(Thread Local Allocation Buffer,本地線程配置設定緩沖),先在緩存區配置設定記憶體,緩沖區滿了之後,配置設定新的緩沖區時同步鎖定。
- VM将配置設定到的記憶體空間都初始化為0(0,null,false等)
- VM對對象進行一些設定,
- 構造函數