[JVM]五 對象在內存中的結構

對象實例化

創建對象的方式:

1)new ,靜態方法創建 , 工廠模式的靜態方法創建
2)class的newInstance() 反射,只能調用空參的構造器,權限必須是public (過時)
3)Constructor的newInstance() 反射,可帶參,無權限要求
4)使用clone() 實現Cloneable接口 淺複製
5)反序列化,從文件或網絡中創建對象
6)第三方庫Objenesis

對象創建的步驟

1)判斷對象對那個的類是否加載,鏈接,初始化

虛擬機首先檢查這個指令的參數能否在Metaspace的常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已經被加載,解析和初始化(即判斷類的元信息是否存在)。如果沒有就根據雙親委派機制使用當前ClassLoader包名類名進行查找當前的.class文件,如果沒有找到文件則拋出ClassNotFoundException異常。如果找到則進行類的加載,並生成對應的class類對象

2)爲對象分配內存

首先計算對象佔用空間(此時對象所佔空間大小已經明確),接着在堆空間劃分一塊內存,如果實例成員變量是引用變量,進分批引用空間即可,即4個字節大小

①如果內存規整,則虛擬機採用指針碰撞法來爲對象分配內存,意思是所有用過的內存存在一邊,空閒的內存存在另一邊,中間放着一個指針作爲分界點的指示器,分配內存就僅僅把指針向空閒那邊移動一段與對象大小相等的距離

②如果內存不規整,(可使用內存是碎片化的),此時 虛擬機需要維護一個空閒列表,列表記錄了內存塊那些是可用的,在分配的時候從列表中找到一塊足夠的空間劃分給對象實例,並更新列表的內容。

選擇那種分配是由java堆是否規整決定,而java堆是否規整又由所採用的垃圾收集器是否帶有壓縮整理功能決定

3)處理併發安全問題,因爲堆空間絕大部分是共享,多個線程new對象就會出現線程安全問題,採用CAS失敗重試,區域加鎖保證更新的原子性。

或每個線程在Eden區域預先分配一塊TLAB 使用參數-XX:±UseTLAB參數設置 JDK8默認開啓

4)屬性默認初始化,所有屬性設置默認值,保證對象實例字段在不賦值時可以使用

5) 設置對象的對象頭,(即類的元數據信息) , 對象的HashCode和對象的GC信息,鎖信息等數據存儲在對象頭中, 由jvm實現

6) init方法初始化,初始化成員變量,執行實例化代碼塊,調用類的構造方法,並把堆內對象的首地址賦值給引用變量。

內存佈局

對象頭

運行時元數據

哈希值
GC年齡分代
鎖狀態標誌
線程持有的鎖
偏向線程ID
偏向時間戳

類型指針

類型指針:指向方法區對象所屬的具體類型

如果對象是數組 還要記錄數組的長度

實例數據

實例數據包括定義的各種類型的字段(包括從父類繼承下來的和本身擁有的字段)

規則:
父類中定義的變量出現在子類之前
同級別相同寬度的字段分配到一起
如果CompactFields參數爲true 子類的窄變量可能插入到父類的空隙

對齊填充

佔位符

對象的訪問定位

即通過引用找到對象的過程

對象的訪問定位是通過棧上引用 reference訪問

對象訪問的兩種方式方式:

句柄訪問

在這裏插入圖片描述
優缺點

缺點:空間消耗,從引用到句柄再到對象實例 效率低

優點:對象引用地址穩定,如果堆空間中對象發生引用,只需要維護句柄池地址

直接指針

在這裏插入圖片描述

直接指針是hostpot虛擬機採用的方式

優缺點

優點:節省空間,從引用直接找到對象實例數據 效率高

缺點:當對象地址變化時,棧空間地址需要做出修改

$.圖:運行時數據區與對象在內存中的結構

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章