1. 對象的建立
1.1 類載入檢查
虛擬機器遇到一條new指令時,首先將去檢查這個指令的參數是否能在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已經被載入、解析和初始化。如果沒有,就先執行相應的類載入過程。 1.2 分配記憶體
從Java堆中劃分出一塊確定大小的記憶體配置給新生對象。
垃圾收集器是否帶有壓縮整理功能決定Java堆是否規整。而Java堆是否規整決定了記憶體的分配方式。 “指標碰撞”:若Java堆中記憶體絕對規整,所有用過的記憶體放一邊,閒置記憶體放在另外一邊,中間放著一個指標作為分界點的指標,那所分配的記憶體就僅僅是把那個指標往空閑空間那邊挪動一段與對象大小相等的距離。 “空閑列表”:若Java堆中的記憶體並不規整,則虛擬機器維護一個列表,記錄哪些記憶體塊是可用的,在分配的時候從列表中找到一塊足夠大的空間劃分給對象執行個體,並更新列表上的記錄。
並發下的安全執行緒 對分配記憶體空間的動作進行同步處理。採用CAS配上失敗重試的方式保證更新操作的原子性。 把記憶體配置的動作按照線程劃分在不同的空間之中進行。每個線程在Java堆中預先分配一小塊記憶體,稱為本地線程分配緩衝(TLAB)。哪個線程要分配記憶體,就在哪個線程的TLAB上分配。只有在TLAB用完並分配新的TLAB時,才需要同步鎖定。 1.3 初始化
虛擬機器將分配到的記憶體空間都初始化為零值(不包括對象頭)。 2. 對象的記憶體布局
在HotSpot虛擬機器中,對象在記憶體中儲存的布局分為3塊地區:對象頭(Header)、執行個體資料(Instance Data)和對齊填充(Padding)。 2.1 對象頭
對象頭包含兩部分資訊: 儲存物件自身的運行時資料,如雜湊碼、GC分代年齡、鎖狀態標誌、線程持有的鎖、偏向線程ID、偏向時間戳記等。 類型指標,即對象指向其類別中繼資料的指標,虛擬機器通過這個指標來確定這個對象是哪個類的執行個體。 3. 對象的訪問定位
Java程式需要通過棧上的reference資料來操作堆上的具體對象。 3.1 使用控制代碼訪問
Java堆會劃分出一塊記憶體來作為控制代碼池,reference中儲存的就是對象的控制代碼地址,而控制代碼中包含了執行個體資料與類型資料各自的具體資訊。
reference->控制代碼池->執行個體池(對象執行個體資料)+ 方法區(物件類型資料)
優勢:reference中儲存的是穩定的控制代碼地址,在對象被移動(垃圾收集時移動對象時非常普遍的行為)時,只會改變控制代碼中的執行個體資料指標,reference本身不需要修改。 3.2 使用直接指標訪問
在Java堆對象中放置訪問類型資料的相關資訊。而reference中儲存的直接就是對象地址。
reference->對象執行個體資料->方法區(物件類型資料)
優勢:速度快,節省了一次指標定位的時間開銷。