第二十二期:New一个对象的时候发生了什么?
如你所知,Java是一門面向對象的編程語言。我們平常在寫代碼的時候也是在不停的操作各種對象,那么當你在寫出User user = new User();這樣一行代碼的時候,JVM都做了些什么呢?
作者:湖人總冠軍
?一、引言
如你所知,Java是一門面向對象的編程語言。我們平常在寫代碼的時候也是在不停的操作各種對象,那么當你在寫出User user = new User();這樣一行代碼的時候,JVM都做了些什么呢?
二、了解對象
1、內存布局
在Hotspot虛擬機中一個對象的內存布局分為三個部分:對象頭、實例數據、對齊填充。
- 對象頭又有兩部分的信息,第一部分是用于存儲對象自身的運行數據(HashCode、GC分代年齡、鎖狀態標志等)。另一部分是類型指針,指向它的類元數據,虛擬機通過這個指針確定這個對象是哪個類的實例(如果使用句柄池方式則不會有)。如果是數組還會有一個記錄數組長度的如下表所示:
Mark Word是一個非固定的數據結構以便在極小的空間內存儲盡量多的信息,它會根據對象的狀態復用自己的存儲空間。各狀態下的存儲內容如下表所示:
- 實例數據部分是真正存儲的有效信息,就是在代碼中定義的各種類型的字段內容。無論是父類繼承下來的,還是在子類中的。
- 對齊填充不是必須存在的,僅僅起著占位符的作用,因為HotSpot虛擬機要求對象的起始地址必須是8字節的整數倍。
2、對象的訪問
Java程序中我們操作一個對象是通過指向這個對象的引用。我們都知道對象存在堆中,這個引用存在虛擬機棧中。那么引用通過什么方式去定位堆中對象的位置呢?
- 直接指針法(HotSpot實現):引用中直接存儲的就是堆中對象的地址。好處就是一次定位速度快,缺點是對象移動(GC時對象移動)引用本身需要修改。
- 句柄法:Java堆中劃分出一部分作為句柄池,引用存儲的是對象的句柄地址,而句柄中包括了對象實例和類型的具體位置信息。好處是對象移動只會改變句柄中的實例數據指針,缺點是兩次定位。
三、創建對象流程
上面介紹了對象的基本信息,現在來講一講創建對象的流程:
分配內存有兩種方式:
- Java堆內存是規整的(使用標記整理或帶壓縮的垃圾收集器),使用一個指針指向空閑位置,分配內存既將指針移動與分配大小相等的距離
- 內存不是規整的(使用標記清除的垃圾收集器),虛擬機維護一個可用內存塊列表,分配內存時從列表中找到一個足夠大的內存空間劃分給對象并更新可用內存列表。
無法找到足夠的內存時會觸發一次GC
分配內存時并發問題解決方案:
- 對分配內存空間的動作進行同步操作---采用CAS失敗重試的方式保證更新操作的原子性。
- 每個線程在堆中預先分配一塊小內存,稱為本地線程分配緩沖(Thread Local Allocation Buffer,TLAB),哪個線程要分配內存就在它的TLAB上分配,只有TLAB用完并分配新的TLAB時才需要同步鎖定。通過-XX:+/-UseTLAB參數來設定。
四、創建對象指令重排序問題
new一個對象的簡單分解動作:
其中2、3兩步間會發生指令重排序,導致多線程時如果在初始化之前訪問對象則會出現問題,單例模式的雙重檢測鎖模式正是會存在這個問題。可以使用volatile來禁止指令重排序解決問題
閱讀目錄(置頂)(長期更新計算機領域知識)
閱讀目錄(置頂)(長期更新計算機領域知識)
閱讀目錄(置頂)(長期科技領域知識)
歌謠帶你看java面試題
?
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的第二十二期:New一个对象的时候发生了什么?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java例子:九九乘法表
- 下一篇: 前端学习(172):格式化文本