new一個對象的時候發生了什麼

1、引言

如你所知,Java是一門面向對象的編程語言。咱們日常在寫代碼的時候也是在不停的操做各類對象,那麼當你在寫出User user = new User();這樣一行代碼的時候,JVM都作了些什麼呢?程序員

2、瞭解對象

一、內存佈局

在Hotspot虛擬機中一個對象的內存佈局分爲三個部分:對象頭、實例數據、對齊填充。編程

  • 對象頭又有兩部分的信息,第一部分是用於存儲對象自身的運行數據(HashCode、GC分代年齡、鎖狀態標誌等)。另外一部分是類型指針,指向它的類元數據,虛擬機經過這個指針肯定這個對象是哪一個類的實例(若是使用句柄池方式則不會有)。若是是數組還會有一個記錄數組長度的以下表所示:數組

    內容 說明
    Mark Word 對象的hashCode或鎖信息等
    Class Metadata Address 對象類型數據指針
    Array length 數組長度

    Mark Word是一個非固定的數據結構以便在極小的空間內存儲儘可能多的信息,它會根據對象的狀態複用本身的存儲空間。各狀態下的存儲內容以下表所示:微信

    標誌位 狀態 存儲內容
    01 未鎖定 對象HashCode、分代年齡
    00 輕量級鎖定 指向鎖記錄的指針
    10 重量級鎖定 指向鎖記錄的指針
    11 GC標記
    01 可偏向 偏向線程ID、偏向時間戳、對象分代年齡
  • 實例數據部分是真正存儲的有效信息,就是在代碼中定義的各類類型的字段內容。不管是父類繼承下來的,仍是在子類中的。數據結構

  • 對齊填充不是必須存在的,僅僅起着佔位符的做用,由於HotSpot虛擬機要求對象的起始地址必須是8字節的整數倍。多線程

二、對象的訪問

Java程序中咱們操做一個對象是經過指向這個對象的引用。咱們都知道對象存在堆中,這個引用存在虛擬機棧中。那麼引用經過什麼方式去定位堆中對象的位置呢?併發

  • 直接指針法(HotSpot實現):引用中直接存儲的就是堆中對象的地址。好處就是一次定位速度快,缺點是對象移動(GC時對象移動)引用自己須要修改。

  • 句柄法:Java堆中劃分出一部分做爲句柄池,引用存儲的是對象的句柄地址,而句柄中包括了對象實例和類型的具體位置信息。好處是對象移動只會改變句柄中的實例數據指針,缺點是兩次定位。

3、建立對象流程

上面介紹了對象的基本信息,如今來說一講建立對象的流程: 編程語言

  1. 當虛擬機遇到一條new指令時,會去檢查這個指令的參數可否在常量池中定位到一個類的符號引用,並檢查表明的類是否已經被類加載器加載。若是沒有被加載那麼必須先執行這個類的加載。
  2. 類加載檢查經過後,虛擬機將爲新對象分配內存,對象所需內存的大小在類加載後即可以肯定。
  3. 內存分配完成後,虛擬機須要將對象初始化爲零值,保證對象的實例變量在代碼中不賦初始值就能直接使用。類變量在類加載的準備階段初始化爲零值。
  4. 對對象頭進行必要信息的設置,好比如何找到類的元數據信息、對象的HashCode、GC分代年齡等。
  5. 通過上述操做,一個新的對象已經產生,可是<init>方法尚未執行,全部的字段都是零值。這時候須要執行<init>方法(構造方法)把對象按照程序員的意願進行初始化。類變量的初始化操做在類加載的初始化階段<clinit>方法完成

分配內存有兩種方式:佈局

  • Java堆內存是規整的(使用標記整理或帶壓縮的垃圾收集器),使用一個指針指向空閒位置,分配內存既將指針移動與分配大小相等的距離
  • 內存不是規整的(使用標記清除的垃圾收集器),虛擬機維護一個可用內存塊列表,分配內存時從列表中找到一個足夠大的內存空間劃分給對象並更新可用內存列表。

沒法找到足夠的內存時會觸發一次GC學習

分配內存時併發問題解決方案:

  • 對分配內存空間的動做進行同步操做---採用CAS失敗重試的方式保證更新操做的原子性。
  • 每一個線程在堆中預先分配一塊小內存,稱爲本地線程分配緩衝(Thread Local Allocation Buffer,TLAB),哪一個線程要分配內存就在它的TLAB上分配,只有TLAB用完並分配新的TLAB時才須要同步鎖定。經過-XX:+/-UseTLAB參數來設定。

4、建立對象指令重排序問題

A a = new A();

new一個對象的簡單分解動做:

  1. 分配對象的內存空間
  2. 初始化對象
  3. 設置引用指向分配的內存地址

其中二、3兩步間會發生指令重排序,致使多線程時若是在初始化以前訪問對象則會出現問題,單例模式的雙重檢測鎖模式正是會存在這個問題。可使用volatile來禁止指令重排序解決問題;





若是有技術問題交流歡迎加我我的微信進羣,你們一塊兒學習😄

二維碼失效添加微信號:JK1048195848

相關文章
相關標籤/搜索