jvm分配內存給對象的方式
1. 內存分配的總體流程
對象內存分配的主要步驟:
- 類加載檢查:確認類已加載、解析和初始化。
- 內存分配:根據對象大小,從堆中劃分內存空間。
- 內存初始化:將分配的內存空間初始化為零值(不包括對象頭)。
- 設置對象頭:填充對象頭信息(如哈希碼、GC 分代年齡、類型指針等)。
- 執行init方法:調用對象的構造函數,初始化成員變量。
2. 內存分配的具體方式
(1)指針碰撞(Bump the Pointer)
- 適用場景:堆內存絕對規整(所有用過的內存放在一邊,空閑的內存放在另一邊)。
- 分配方式:JVM 維護一個指針,指向空閑內存的起始位置。分配時,將指針向空閑方向移動對象大小的距離。
- 優點:高效,僅需移動指針。
- 缺點:需要內存規整,依賴垃圾回收器(如 Serial、ParNew 等帶有壓縮功能的 GC)。
(2)空閑列表(Free List)
- 適用場景:堆內存不規整(已使用和空閑內存交錯)。
- 分配方式:JVM 維護一個記錄空閑內存塊的列表,分配時從列表中找到足夠大的塊,并更新列表。
- 優點:適合不規整內存,無需內存壓縮。
- 缺點:分配效率較低,需遍歷列表并維護列表結構。
- 應用:CMS 等基于 “標記 - 清除” 的垃圾回收器使用此方式。
3. 線程安全的內存分配
對象創建在多線程環境下是線程不安全的,可能出現多個線程同時分配同一塊內存的問題。JVM 采用兩種方式解決:
(1)CAS(Compare-and-Swap)
- 執行流程:
1. 線程讀取共享變量 V 的當前值
2. 將讀取的值存儲為預期舊值 A
3. 計算需要更新的新值 B
4. 執行 CAS 操作,比較 V 的當前值是否等于 A:- 如果相等(說明期間沒有其他線程修改 V),則原子性地將 V 的值更新為 B- 如果不相等(說明其他線程已修改 V),則操作失敗,通常需要重試或放棄
- 缺點:若競爭激烈,頻繁的 CAS 失敗會導致性能下降。
(2)TLAB(Thread Local Allocation Buffer)
- 機制:為每個線程預先分配一小塊私有內存(TLAB),線程內的對象分配優先在 TLAB 中進行,避免同步開銷。
jvm對象的內存布局
在 JVM(Java 虛擬機)中,對象在內存中的布局主要分為三個部分:對象頭(Object Header)、實例數據(Instance Data)?和?對齊填充(Padding)。
1. 對象頭(Object Header)
對象頭包含兩部分信息:Mark Word?和?類型指針(Class Pointer),某些情況下還會包含?數組長度(如果對象是數組)。
Mark Word
- 作用:存儲對象的哈希碼、鎖狀態標志、GC 分代年齡等運行時數據。
- 長度:在 32 位 JVM 中占 32 位(4 字節),64 位 JVM 中占 64 位(8 字節)。
類型指針(Class Pointer)
- 作用:指向對象的類元數據(Class 對象),JVM 通過這個指針確定對象是哪個類的實例。
- 長度:32 位 JVM 中占 32 位(4 字節),64 位 JVM 中默認開啟指針壓縮時占 32 位(4 字節),否則占 64 位(8 字節)。
數組長度(可選)
- 作用:如果對象是數組,對象頭中會額外存儲數組的長度。
- 長度:32 位(4 字節)。
2. 實例數據(Instance Data)
- 作用:存儲對象的字段數據,包括父類繼承的和子類定義的字段。
- 布局規則:
- 相同寬度的字段被分配在一起(例如,int?和?float?都是 4 字節,可能相鄰)。
- 父類字段在前,子類字段在后。
- 遵循 JVM 對齊規則:字段會按照 8 字節對齊(64 位 JVM)。
3. 對齊填充(Padding)
- 作用:JVM 要求對象的總大小必須是 8 字節的整數倍,不足的部分用填充字節補齊。
- 原因:提高內存訪問效率,避免跨緩存行訪問。
jvm對象的訪問方式
在 JVM(Java 虛擬機)中,對象的訪問方式主要涉及?引用(Reference)?如何定位到具體的對象實例。JVM 提供了兩種主流的對象訪問方式:句柄訪問?和?直接指針訪問
1. 句柄訪問(Handle Access)
原理
- 句柄池:JVM 在堆中劃分一塊區域作為句柄池,每個句柄包含兩部分指針:
- 引用指向:Java 引用(如?Object obj = new Object()?中的?obj)存儲的是句柄池中的句柄地址。
訪問流程
引用變量(棧) → 句柄池(堆) → 對象實例數據(堆)→ 對象類型數據(方法區)
優缺點
- 優點:引用穩定,對象移動時只需修改句柄中的指針,無需修改引用本身。
- 缺點:需要兩次指針訪問(先到句柄池,再到對象),性能略低。
2. 直接指針訪問(HotSpot 采用)
原理
- 引用指向:Java 引用直接存儲對象在堆中的地址,對象的實例數據中包含?類型指針,指向方法區的類元數據。
訪問流程
引用變量(棧) → 對象實例數據(堆) → 對象類型數據(方法區)
優缺點
- 優點:訪問速度快,只需一次指針訪問。
- 缺點:對象移動 時需要修改所有引用的指針。
總結
- 句柄訪問:通過句柄池間接訪問對象,優點是引用穩定,缺點是性能較低。
- 直接指針訪問:引用直接指向對象,優點是性能高,缺點是對象移動時需修改引用。