Java堆中對象建立、佈局、訪問全過程

1.建立對象

    建立對象一般僅僅是一個new關鍵詞而已。程序員

1.1類加載檢查

    虛擬機在建立對象以前須要先判斷是否已經被加載,經過檢查這個指令的參數是否能在常量池中定位到一個類的符號引用,而且檢查這個符號引用表明的類是否已被加載、解析和初始化過。若是沒有,那必須先執行相應的類的加載過程。算法

1.2爲對象分配內存空間

    對象所需內存的大小在類加載完成後便徹底肯定,爲對象分配空間的任務等同於把一塊肯定大小的內存從Java堆中劃分出來。緩存

1.2.1內存分配方式

    根據Java堆中的內存是否規整有兩種內存的分配方式指針碰撞方式和空閒列表方式,Java堆是否規整由所採用的垃圾收集器是否帶有壓縮整理功能決定。安全

  • 指針碰撞(Bump the pointer):Java堆中的內存是規整的,全部用過的內存都放在一邊,空閒的內存放在另外一邊,中間放着一個指針做爲分界點的指示器,分配內存也就是把指針向空閒空間那邊移動一段與內存大小相等的距離。例如:Serial、ParNew等收集器。
  • 空閒列表(Free List):Java堆中的內存不是規整的,已使用的內存和空閒的內存相互交錯,就沒有辦法簡單的進行指針碰撞了。虛擬機必須維護一張列表,記錄哪些內存塊是可用的,在分配的時候從列表中找到一塊足夠大的空間劃分給對象實例,並更新列表上的記錄。例如:
    CMS這種基於Mark-Sweep算法的收集器。

1.2.2內存分配時的併發問題

    對象在虛擬機中建立時很是頻繁的行爲,即便是僅僅修改一個指針指向的位置,在併發狀況下也並非線程安全的,可能出現正在給對象A分配內存,指針還沒來得及修改,對象B又同時使用了原來的指針來分配內存的狀況。解決這個問題有兩種方案,一種是同步處理另外一種是本地線程分配緩存。併發

  • 同步處理:對分配內存空間的動做進行同步處理——實際上虛擬機採用CAS配上失敗重試的方式保證更新操做的原子性。
  • 本地線程緩衝(TLAB):把內存分配的動做按照線程劃分爲在不一樣的空間之中進行,即每一個線程在Java堆中預先分配一小塊內存,稱爲本地線程分配緩衝(Thread Local Allocation Buffer,TLAB)。哪一個線程要分配內存,就在哪一個線程的TLAB上分配。只有TLAB用完並分配新的TLAB時,才須要同步鎖定。虛擬機是否使用TLAB,能夠經過-XX:+/UserTLAB參數來設置。

1.3內存空間初始化

    虛擬機將分配到的內存空間都初始化爲零值(不包括對象頭),若是使用了TLAB,這一工做過程也能夠提早至TLAB分配時進行。內存空間初始化保證了對象的實例字段在Java代碼中能夠不賦初始值就直接使用,程序能訪問到這些字段的數據類型所對應的零值。 spa

1.4設置對象

    虛擬機對對象進行必要的設置,例如這個對象是哪一個類的實例、如何才能找到類的元數據信息、對象的哈希碼、對象的GC分代年齡等信息。這些信息存放在對象的對象頭之中。線程

1.5執行<init>方法

    在上面的工做都完成以後,從虛擬機的角度看,一個新的對象已經產生了。可是從Java程序的角度看,對象的建立纔剛剛開始<init>方法尚未執行,全部的字段都仍是零。因此,通常來講(由字節碼中是否跟隨invokespecial指令所決定),執行new指令以後會接着執行<init>方法,把對象按照程序員的意願進行初始化,這樣一個真正可用的對象纔算產生出來。指針

相關文章
相關標籤/搜索