對象的創建過程

  1. 虛擬機遇到一條new指令時,首先將去檢查這個指令的參數是否在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已被加載、解析和初始化過。如果沒有,那必須執行相應的類加載過程。

  2. 類加載檢查通過後,接下來虛擬機將爲新生對象分配內存。對象所需的內存的大小在類加載完成後便可完全確定。內存分配又有兩種方式:指針碰撞(Bump the Pointer)和空閒列表(Free List)。選用哪種分配方式由堆是否規整來決定,而堆是否規整又由垃圾收集器是否帶有壓縮整理功能決定。

    ​ 在Serial、ParNew等帶有compact過程的收集器,系統採用的分配算法是指針碰撞,而使用CMS這種基於Mark-Sweep算法的收集器時,通常採用空閒列表。

    ​ 除了如何劃分空間之外,還要考慮併發情況下線程安全問題。由兩種解決方案:

    1. 分配內存空間的動作進行同步處理-實際上虛擬機採用CAS配上失敗重試的方式保證更新操作的原子性。

    2. 把內存分配的動作按照線程劃分在不同的空間中進行,即每個線程在Java堆中預先分配一小塊內存,稱爲本地線程分配緩衝(Thread Local Allocation Buffer, TLAB),哪個線程要分配內存,就在哪個線程的TLAB上分配。只有TLAB用完並分配新的TLAB時,才需要同步鎖定。可以通過-XX:+/-UseTLAB參數來設定。

  3. 分配完內存後,虛擬機需要將分配到的內存空間初始化爲0值(不包括對象頭),如果使用TLAB,這一工作過程可以提前至TLAB分配時進行,這一操作保證了對象的實例字段在Java代碼中可以不賦初始值就直接使用。

  4. 設置對象頭(Object Header),對象是哪個類實例、如何才能找到類的元數據信息、對象哈希碼、對象的GC分代年齡等信息。

  5. 上面工作完成之後,從虛擬機角度來看,一個新的對象已經產生了,但從Java程序視角來看,對象的創建纔剛剛開始-<init>方法還沒有執行,所有字段還都爲0。

發佈了311 篇原創文章 · 獲贊 114 · 訪問量 39萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章