JVM學習 物件的例項化 記憶體布局與訪問定位

2021-10-07 15:04:37 字數 2006 閱讀 9894

1、判斷物件對應的類是否載入、鏈結、初始化

虛擬機器遇到一條 new 指令的時候,首先去方法去中查詢這個類是否被載入過。如果沒有,在雙親委派機制模式下,使用當前類載入器 classloader + 包名 + 類名 作為 key 查詢對應的 .class 檔案,沒有找到丟擲 classnotfoundexception 異常,找到的話則進行類載入,生成對應的 class 類物件

2、為物件分配記憶體

計算物件占用空間大小,接著在堆中劃分一塊記憶體給新物件

3、處理分配物件記憶體時的併發問題

堆是執行緒共享的,所以在多執行緒情況下分配物件可能會有併發問題。一般會優先分配在每個執行緒的 tlab 中,分配失敗的話,會採用 cas 失敗重試、加鎖來保證分配的原子性

4、為物件屬性預設初始化

也就是給物件屬性賦零值

5、設定物件的物件頭

將物件的所屬類(類的元資料資訊)、物件的 hashcode 、gc資訊、鎖資訊等資料儲存在物件頭中。也就是將物件指向方法區中的類資訊,將兩者關聯起來

6、執行 init 方法進行初始化

也就是顯示初始化。如果站在程式的角度來看的話,這一步才算初始化的正式開始,在這一步會初始化成員變數,執行例項化**塊,呼叫類的構造方法等來初始化物件

大家都知道,如果 new 乙個物件,就是在堆空間中開闢了一塊記憶體,但是這塊記憶體的布局是什麼樣的呢?主要包括 3 部分

主要包含兩部分

(1)執行時元資料

gc分代的年齡:也就是物件的年齡,在 gc 的時候會使用

鎖狀態標誌

執行緒持有的鎖

偏向執行緒 id

偏向時間戳

2)型別指標

指向方法區中這個物件所屬的型別。也就是說每個物件都知道它的類是誰,就是由這個型別指標確定的。

注:如果建立的是陣列(陣列也是乙個物件,也放在方法區中),還需要記錄陣列的長度。

主要就是**中定義的各種型別的字段(不光是自己類中的,還包括從父類繼承下來的)

不是必須的,沒什麼特別含義,僅僅起到佔位符的作用

先定義如下**:

public class customer 

public customer()

}class account

/** * 主方法

*/public class newtest

}

在如上**中對應的記憶體圖如下:

主線程中 main() 方法入棧。main() 方法棧幀的區域性變數表中有兩個變數,乙個是方法引數 args,乙個是自己建立的customer類的物件 cust。

我們在 new customer() 後,會在堆空間建立乙個 customer 例項。區域性變數表中 cust 指向堆空間中建立的物件例項。

在 customer類的物件例項中,有物件的資訊。包括物件頭資訊、例項資料資訊。在例項資料資訊中,有父類的例項資料,還有自己定義的例項資料,其中 id 值為 1,name 的值指向堆空間中的字串常量中的 "匿名客戶",acct 指向 account 類的例項。

customer 物件例項中的型別指向方法區中 customer 類的 class 資訊。account 物件例項中的型別指向方法區中 account類的 class 資訊。

通過以上關係圖,就很清晰的知道了棧、堆、方法區之間的聯絡了

hotspot 採用的就是指標的方法。棧中物件引用直接指向堆空間中的物件例項,堆空間中物件例項中的型別指標又指向方法區中該類的類元資訊。具體如下如所示:

JVM物件例項化

new 最常見的方法 的靜態方法 builder factory的靜態方法 class 的 newinstance 8中能用,9已經標註過時了,反射的方式,只能呼叫空參的構造器,許可權必須是public。constructor 的 newinstance 反射的方式,可以呼叫空參,帶參,取代了第二個...

jvm 物件在記憶體中儲存的布局

jvm 物件在記憶體中儲存的布局有三部分 物件頭 例項資料 對齊填充。1 物件頭 執行時資料 型別指標 陣列長度。1 執行時資料 hashcode雜湊碼 鎖狀態標誌 執行緒持有的鎖 gc年齡分代等,有些不是固定不變的,在執行時會根據當時的狀態進行修改。2 型別指標 指向方法區中型別資訊的指標。型別資...

JVM 物件例項化過程 6個階段

處理併發問題 預設賦值 設定物件頭資訊 顯式初始化 package xyz.xx.chapter10 變數初始化順序測試 xiaoming 30 false 40 public class variableinitialtest 類載入的6個階段 載入類元資訊 分配記憶體 記憶體規整 記憶體不規整 ...