如你所知,Java是一門面向對象的編程語言。咱們日常在寫代碼的時候也是在不停的操做各類對象,那麼當你在寫出User user = new User();
這樣一行代碼的時候,JVM都作了些什麼呢?程序員
在Hotspot虛擬機中一個對象的內存佈局分爲三個部分:對象頭、實例數據、對齊填充。編程
對象頭又有兩部分的信息,第一部分是用於存儲對象自身的運行數據(HashCode、GC分代年齡、鎖狀態標誌等)。另外一部分是類型指針,指向它的類元數據,虛擬機經過這個指針肯定這個對象是哪一個類的實例(若是使用句柄池方式則不會有)。若是是數組還會有一個記錄數組長度的以下表所示:數組
內容 | 說明 |
---|---|
Mark Word | 對象的hashCode或鎖信息等 |
Class Metadata Address | 對象類型數據指針 |
Array length | 數組長度 |
Mark Word是一個非固定的數據結構以便在極小的空間內存儲儘可能多的信息,它會根據對象的狀態複用本身的存儲空間。各狀態下的存儲內容以下表所示:微信
標誌位 | 狀態 | 存儲內容 |
---|---|---|
01 | 未鎖定 | 對象HashCode、分代年齡 |
00 | 輕量級鎖定 | 指向鎖記錄的指針 |
10 | 重量級鎖定 | 指向鎖記錄的指針 |
11 | GC標記 | 空 |
01 | 可偏向 | 偏向線程ID、偏向時間戳、對象分代年齡 |
實例數據部分是真正存儲的有效信息,就是在代碼中定義的各類類型的字段內容。不管是父類繼承下來的,仍是在子類中的。數據結構
對齊填充不是必須存在的,僅僅起着佔位符的做用,由於HotSpot虛擬機要求對象的起始地址必須是8字節的整數倍。多線程
Java程序中咱們操做一個對象是經過指向這個對象的引用。咱們都知道對象存在堆中,這個引用存在虛擬機棧中。那麼引用經過什麼方式去定位堆中對象的位置呢?併發
上面介紹了對象的基本信息,如今來說一講建立對象的流程: 編程語言
分配內存有兩種方式:佈局
沒法找到足夠的內存時會觸發一次GC學習
分配內存時併發問題解決方案:
A a = new A();
new一個對象的簡單分解動做:
其中二、3兩步間會發生指令重排序,致使多線程時若是在初始化以前訪問對象則會出現問題,單例模式的雙重檢測鎖模式正是會存在這個問題。可使用volatile來禁止指令重排序解決問題;
若是有技術問題交流歡迎加我我的微信進羣,你們一塊兒學習😄
二維碼失效添加微信號:JK1048195848