11.28 當你寫出User user = new User()時,JVM 都做了些什麼

當你寫出User user = new User()時,JVM 都做了些什麼

一、引言

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

二、瞭解對象

1、內存佈局

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

  • 對象頭又有兩部分的信息,第一部分是用於存儲對象自身的運行數據(HashCode、GC分代年齡、鎖狀態標誌等)。另一部分是類型指針,指向它的類元數據,虛擬機通過這個指針確定這個對象是哪個類的實例(如果使用句柄池方式則不會有)。如果是數組還會有一個記錄數組長度的如下表所示:
當你寫出User user = new User()時,JVM 都做了些什麼

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

當你寫出User user = new User()時,JVM 都做了些什麼

  • 實例數據部分是真正存儲的有效信息,就是在代碼中定義的各種類型的字段內容。無論是父類繼承下來的,還是在子類中的。
  • 對齊填充不是必須存在的,僅僅起著佔位符的作用,因為HotSpot虛擬機要求對象的起始地址必須是8字節的整數倍。

2、對象的訪問

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

  • 直接指針法(HotSpot實現):引用中直接存儲的就是堆中對象的地址。好處就是一次定位速度快,缺點是對象移動(GC時對象移動)引用本身需要修改。
當你寫出User user = new User()時,JVM 都做了些什麼

  • 句柄法:Java堆中劃分出一部分作為句柄池,引用存儲的是對象的句柄地址,而句柄中包括了對象實例和類型的具體位置信息。好處是對象移動只會改變句柄中的實例數據指針,缺點是兩次定位。
當你寫出User user = new User()時,JVM 都做了些什麼

三、創建對象流程

上面介紹了對象的基本信息,現在來講一講創建對象的流程:

當你寫出User user = new User()時,JVM 都做了些什麼

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

分配內存有兩種方式:

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

無法找到足夠的內存時會觸發一次GC

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

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

四、創建對象指令重排序問題

A a = new A();

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

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

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

鏈接:https://juejin.im/post/5da971216fb9a04e17209328

關注我瞭解更多程序員資訊技術,領取豐富架構資料


分享到:


相關文章: