天天看點

對象的建立過程

  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​

    ​參數來設定。
  1. 配置設定完記憶體後,虛拟機需要将配置設定到的記憶體空間初始化為0值(不包括對象頭),如果使用TLAB,這一工作過程可以提前至TLAB配置設定時進行,這一操作保證了對象的執行個體字段在Java代碼中可以不賦初始值就直接使用。
  2. 設定對象頭(Object Header),對象是哪個類執行個體、如何才能找到類的中繼資料資訊、對象哈希碼、對象的GC分代年齡等資訊。
  3. 上面工作完成之後,從虛拟機角度來看,一個新的對象已經産生了,但從Java程式視角來看,對象的建立才剛剛開始-<init>方法還沒有執行,所有字段還都為0。