JVM創(chuàng)建對象的過程

僅討論創(chuàng)建普通的Java對象,不包括數(shù)組、Class對象等

1.類加載校驗

虛擬機遇到new指令時,首先會去檢查這個符號引用代表的類是否已經(jīng)被加載、解析和初始化過(方法區(qū)中是否存在)。如果沒有那必須先進行類加載過程。

2.分配內(nèi)存

對象所需要的內(nèi)存的大小在類加載之后就能完全確定。為對象分配空間的任務(wù)等同于將一塊確定大小的內(nèi)存空間從Java堆中劃分出來。

指針碰撞(Bump the Pointer)分配內(nèi)存

假設(shè)所有的Java堆內(nèi)存都是絕對規(guī)整的。通過一個指針來區(qū)分已分配的內(nèi)存和未分配的內(nèi)存,每次分配內(nèi)存都是移動指針。這種分配內(nèi)存的方式叫做指針碰撞。

空閑列表(Free List)分配內(nèi)存

假設(shè)所有的Java內(nèi)存不是絕對規(guī)整的。虛擬機就需要通過一個表記錄未分配的內(nèi)存塊,分配的時候在表中找到一個滿足的內(nèi)存塊,并更新表。
Java堆的內(nèi)存是否規(guī)整由所采用的垃圾收集器是否帶有壓縮整理功能決定。在使用Serial、ParNew等帶Compact過程的收集器中,采用的是指針碰撞分配內(nèi)存;如果使用的是CMS這種基于Mark-Sweep算法的收集器時,使用的是空閑列表分配內(nèi)存。
除了如何劃分可用空間之外,還需要考慮創(chuàng)建對象的并發(fā)問題。解決這個問題由兩種方式:

  • CAS失敗重試保證原子性
  • 將內(nèi)存分配的動作按線程劃分在不同的空間之中(線程隔離)

采用線程隔離的時候,每個線程預先分配的空間叫做本地線程分配緩沖(Thread Local Allocation Buffer TLAB)。當TLAB用完的時候,需要同步鎖定分配,并分配新的TLAB。虛擬機是否使用TLAB,可以通過-XX:+-UseTLAB參數(shù)來設(shè)定

3.初始化內(nèi)存空間為零值

內(nèi)存分配完成后,虛擬機需要將分配到的內(nèi)存空間都初始化為零值(不包括對象頭),如果使用TLAB,這一過程可以提前到TLAB分配對象內(nèi)存空間時進行。這一步操作保證了對象的實例字段在不賦初值時就能夠直接使用。

4.設(shè)置對象的對象頭

設(shè)置這個對象的類信息、類的元數(shù)據(jù)信息、對象的哈希嗎、對象的GC分代年齡等信息,將他們存放到對象頭中。根據(jù)虛擬機當前的運行狀態(tài)的不同(如是否開啟偏向鎖),會對對象頭有不同的設(shè)置方式。

5.對象的初始化

對于JVM來說,對象已經(jīng)創(chuàng)建完畢,但對于Java程序來說,對象創(chuàng)建才剛剛開始。這時所有的字段都為零值。這時對象會執(zhí)行init方法,初始化對象。

本文摘錄自深入理解Java虛擬機
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容