亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java的對象頭原理與源碼超詳細講解

 更新時間:2025年08月06日 09:54:24   作者:goTsHgo  
Java對象頭是對象內(nèi)存布局的核心部分,存儲元數(shù)據(jù)和運行時狀態(tài),這篇文章主要介紹了Java的對象頭原理與源碼超詳細講解的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

前言

本文將從底層原理和源代碼層面詳細解釋Java的對象頭(Object Header),并且盡量用通俗易懂的語言讓初學者也能理解。首先從概念開始,逐步深入到實現(xiàn)細節(jié),涵蓋對象頭的結(jié)構(gòu)、作用、源碼分析,并提供完整的步驟和推導。內(nèi)容清晰、結(jié)構(gòu)化,避免過于晦澀的技術(shù)術(shù)語。由于對象頭是Java鎖機制(如synchronized)的基礎(chǔ),我會適當結(jié)合鎖的場景來增強理解。

一、什么是Java對象頭?為什么需要它?

1.1 對象頭的概念

 在Java中,每個對象(比如new Object()創(chuàng)建的對象)在內(nèi)存中不僅存儲了它的實際數(shù)據(jù)(字段值),還有一個額外的“標簽”部分,稱為對象頭(Object Header)。你可以把對象頭想象成一個身份證,記錄了對象的身份信息和狀態(tài),比如:

  • 這個對象是否被鎖???
  • 這個對象屬于哪個類?
  • 這個對象的年齡(用于垃圾回收)?

對象頭就像一個“管理面板”,JVM(Java虛擬機)通過它來管理對象的生命周期、鎖狀態(tài)和內(nèi)存分配。

1.2 為什么需要對象頭?

對象頭的主要作用是為JVM提供元數(shù)據(jù)(Metadata),支持以下功能:

  1. 鎖機制:實現(xiàn)synchronized鎖,記錄鎖狀態(tài)(比如哪個線程持有鎖)。
  2. 垃圾回收:記錄對象的分代年齡(GC Age),決定對象是否需要被回收。
  3. 類型信息:指向?qū)ο蟮念愋畔?,確保JVM知道這個對象是哪個類的實例。
  4. 哈希碼:存儲對象的hashCode()值,用于HashMap等數(shù)據(jù)結(jié)構(gòu)。
  5. 數(shù)組支持:如果對象是數(shù)組,記錄數(shù)組長度。

沒有對象頭,JVM就無法高效管理對象,也無法實現(xiàn)多線程的線程安全。

二、Java對象頭的結(jié)構(gòu)

Java對象頭的結(jié)構(gòu)在JVM實現(xiàn)中(以HotSpot JVM為主)分為幾個部分,主要包括:

  1. Mark Word:動態(tài)變化的部分,存儲鎖狀態(tài)、哈希碼、分代年齡等。
  2. Class Metadata Address:指向?qū)ο笏鶎兕惖脑獢?shù)據(jù)地址。
  3. Array Length(可選):如果對象是數(shù)組,存儲數(shù)組長度。

以下是對象頭在內(nèi)存中的典型布局(以64位JVM為例,假設(shè)未開啟指針壓縮):

部分大?。?4位JVM)描述
Mark Word8字節(jié)(64位)鎖狀態(tài)、哈希碼、GC年齡等
Class Metadata Address8字節(jié)(64位)指向類的元數(shù)據(jù)地址
Array Length4字節(jié)(可選)數(shù)組長度(僅數(shù)組對象有)

2.1 Mark Word

Mark Word 是對象頭中最復雜、最動態(tài)的部分。它的內(nèi)容會根據(jù)對象狀態(tài)(無鎖、鎖住、GC標記等)變化。Mark Word 通常包含以下信息:

  • 鎖狀態(tài):無鎖、偏向鎖、輕量級鎖、重量級鎖。
  • 線程ID:持有鎖的線程ID(偏向鎖時)。
  • 哈希碼:對象的hashCode()值。
  • 分代年齡:用于垃圾回收,記錄對象經(jīng)歷的GC次數(shù)。
  • 鎖記錄指針:輕量級鎖或重量級鎖時,指向鎖記錄或Monitor。

Mark Word 的結(jié)構(gòu)會根據(jù)鎖狀態(tài)動態(tài)調(diào)整。例如,在無鎖狀態(tài)下,它會存儲哈希碼和GC年齡;在鎖住狀態(tài)下,它會存儲線程ID或Monitor指針。

以下是 Mark Word 在不同狀態(tài)下的典型布局(64位JVM,未壓縮指針):

鎖狀態(tài)63-56bit55-2bit1-0bit(鎖標志)
無鎖GC年齡對象的哈希碼01
偏向鎖線程IDEpoch01
輕量級鎖指向鎖記錄的指針00
重量級鎖指向Monitor的指針10
GC標記GC相關(guān)信息11

完整位劃分

狀態(tài)位范圍字段名大?。ㄎ唬?/th>說明
無鎖63-31未使用33保留位,通常為 0,未來可能擴展使用。
30-8哈希碼 (hash)23對象的 hashCode() 值,調(diào)用 System.identityHashCode() 時生成。
7-4分代年齡 (age)4垃圾回收年齡,記錄對象經(jīng)歷的 Minor GC 次數(shù)(最大 15)。
3-2未使用2保留位,通常為 0。
1-0鎖標志位201,表示無鎖狀態(tài)。
偏向鎖63-56未使用8保留位,通常為 0。
55-8線程 ID48持有偏向鎖的線程 ID,標識哪個線程“偏向”這個對象。
7-6Epoch2偏向鎖的時間戳,用于批量撤銷偏向鎖(優(yōu)化機制)。
5-4分代年齡 (age)4同無鎖狀態(tài),記錄 GC 年齡。
3偏向鎖標志11,表示是偏向鎖(與無鎖區(qū)分)。
2-1未使用2保留位,通常為 0。
0鎖標志位11,與偏向鎖標志一起組成 01(最低 2 位)。
輕量級鎖63-2鎖記錄指針62指向線程棧中的鎖記錄(Displaced Header),保存原來的 Mark Word。
1-0鎖標志位200,表示輕量級鎖狀態(tài)。
重量級鎖63-2Monitor 指針62指向 ObjectMonitor 實例(操作系統(tǒng)級互斥鎖)。
1-0鎖標志位210,表示重量級鎖狀態(tài)。
GC 標記63-2GC 相關(guān)信息62存儲垃圾回收標記信息(如對象是否存活,具體由 GC 算法決定)。
1-0鎖標志位211,表示 GC 標記狀態(tài)。

32位JVM中是這么存的:

鎖狀態(tài)

25bit

4bit

1bit

2bit

23bit

2bit

是否偏向鎖

鎖標志位

無鎖

對象的哈希碼

分代年齡

0

01

偏向鎖

線程ID

Epoch

分代年齡

1

01

輕量級鎖

指向棧中鎖記錄的指針

00

重量級鎖

指向重量級鎖的指針

10

GC標記

11

通俗解釋

  • Mark Word 像一個多功能顯示屏,顯示的內(nèi)容根據(jù)對象狀態(tài)切換。
  • 比如,對象沒被鎖時,顯示“哈希碼”和“GC年齡”;被鎖住時,顯示“鎖信息”和“線程ID”。

2.2 Class Metadata Address

這部分是一個指針,指向?qū)ο笏鶎兕惖脑獢?shù)據(jù)(Class Metadata),存儲在JVM的方法區(qū)(或元空間)。元數(shù)據(jù)包含類的結(jié)構(gòu)信息,比如:

  • 類名、父類、接口。
  • 方法表、字段表。
  • 靜態(tài)變量等。

通俗解釋

  • 就像身份證上的“籍貫”,告訴JVM這個對象是哪個類的實例。
  • JVM通過這個指針找到類的“藍圖”,知道如何操作這個對象。

2.3 Array Length

如果對象是數(shù)組(比如int[ ]),對象頭會額外包含一個4字節(jié)的字段,記錄數(shù)組的長度。普通對象沒有這一部分。

通俗解釋

  • 數(shù)組就像一個貨架,Array Length 告訴你貨架上有多少格子。

三、對象頭的作用和底層原理

3.1 對象頭在鎖機制中的作用

對象頭是synchronized鎖的核心,因為它存儲了鎖狀態(tài)和Monitor信息。以下是synchronized鎖的工作原理與對象頭的關(guān)聯(lián):

  1. 無鎖狀態(tài)

    • Mark Word 存儲哈希碼和GC年齡,鎖標志位是01。
    • 對象未被任何線程鎖定。
  2. 偏向鎖

    • 當一個線程首次獲取鎖時,JVM將Mark Word中的線程ID設(shè)為該線程ID,鎖標志位仍為01。
    • 偏向鎖假設(shè)鎖通常被同一線程持有,減少鎖獲取的開銷。
    • 例如:Mark Word 記錄“線程A的ID”,下次線程A再獲取鎖時,直接檢查ID,無需額外操作。
  3. 輕量級鎖

    • 如果有輕微競爭(比如另一個線程嘗試獲取鎖),JVM將鎖升級為輕量級鎖。
    • Mark Word 存儲一個指向鎖記錄的指針(如線程棧中的記錄),鎖標志位變?yōu)?code>00。
    • 鎖記錄保存了原來的Mark Word內(nèi)容,釋放鎖時恢復。
  4. 重量級鎖

    • 如果競爭激烈(多個線程爭搶鎖),JVM將鎖升級為重量級鎖。
    • Mark Word 存儲一個指向Monitor的指針,鎖標志位變?yōu)?code>10。
    • Monitor 是一個操作系統(tǒng)級別的互斥鎖(Mutex),管理線程的等待和喚醒。

通俗例子

  • 想象對象是一個房間,Mark Word 是門上的鎖。
  • 無鎖:門沒鎖,任何人都能進。
  • 偏向鎖:門上貼了“只許小明進”的標簽,小明不用每次都開鎖。
  • 輕量級鎖:小明和朋友輪流用鑰匙開鎖,稍微麻煩點。
  • 重量級鎖:請了個保安(Monitor)守門,所有人排隊登記才能進。

3.2 對象頭在垃圾回收中的作用

Mark Word 中的分代年齡(GC Age)用于JVM的分代垃圾回收(Generational GC):

  • 每次對象在Minor GC中存活,年齡加1。
  • 年齡達到閾值(默認15),對象晉升到老年代。
  • Mark Word 的GC標記位(11)在GC期間用于標記對象是否存活。

通俗解釋

  • 分代年齡就像人的年齡,記錄對象“活了多久”。
  • JVM通過年齡判斷對象是否“老了”,決定是否搬到“養(yǎng)老院”(老年代)。

3.3 對象頭在哈希碼中的作用

當調(diào)用對象的hashCode()方法時,JVM將哈希碼存儲在Mark Word中。如果對象被鎖住,哈希碼可能被暫時移到Monitor或鎖記錄中。

通俗解釋

  • 哈希碼就像對象的“身份證號”,用于HashMap等場景。
  • Mark Word 是身份證的“號碼欄”,鎖住時號碼可能被臨時抄到別處。

四、對象頭的源碼分析

對象頭的實現(xiàn)主要在HotSpot JVM的C++代碼中,位于src/hotspot/share/oops/目錄。我們重點分析Mark Word和相關(guān)邏輯。

4.1 Mark Word的定義

在HotSpot JVM中,Mark Word 由markOop類表示,定義在markOop.hpp中:

// src/hotspot/share/oops/markOop.hpp
class markOopDesc : public oopDesc {
private:
  uintptr_t _value; // Mark Word的實際值(64位機器上是64位)

public:
  // 獲取鎖狀態(tài)
  inline uintptr_t lock_bits() const {
    return (_value & lock_mask_in_place);
  }

  // 獲取線程ID(偏向鎖)
  inline uintptr_t biased_thread_id() const {
    return (_value >> biased_lock_thread_id_shift);
  }

  // 獲取哈希碼
  inline uintptr_t hash() const {
    return (_value >> hash_shift) & hash_mask;
  }

  // 獲取分代年齡
  inline uintptr_t age() const {
    return (_value >> age_shift) & age_mask;
  }
};

關(guān)鍵點解釋

  • _value 是一個64位整數(shù),存儲Mark Word的所有信息。
  • 通過位運算(>>、&)提取鎖狀態(tài)、線程ID、哈希碼、年齡等。
  • 鎖標志位(最低2位)決定Mark Word的當前狀態(tài)(01、00、10、11)。

4.2 對象頭的內(nèi)存布局

HotSpot JVM中,對象的內(nèi)存布局由oopDesc類定義,位于oop.hpp:

// src/hotspot/share/oops/oop.hpp
class oopDesc {
private:
  volatile markOop _mark; // Mark Word
  Klass* _metadata;       // Class Metadata Address
};
  • _mark:Mark Word,存儲鎖狀態(tài)等。
  • _metadata:指向類元數(shù)據(jù)的指針。

如果對象是數(shù)組,還會額外包含數(shù)組長度字段(由JVM在分配內(nèi)存時添加)。

4.3 鎖狀態(tài)的切換邏輯

鎖狀態(tài)的切換在 synchronizer.cpp 中實現(xiàn),涉及偏向鎖、輕量級鎖、重量級鎖的轉(zhuǎn)換。以下是簡化邏輯:

// src/hotspot/share/runtime/synchronizer.cpp
void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, Thread* self) {
  markOop mark = obj->mark(); // 獲取Mark Word

  if (mark->is_neutral()) { // 無鎖狀態(tài)
    // 嘗試偏向鎖
    if (UseBiasedLocking) {
      markOop biased = mark->biased_to(self); // 設(shè)置線程ID
      if (Atomic::cmpxchg(biased, obj->mark_addr(), mark) == mark) {
        return; // 偏向成功
      }
    }
    // 嘗試輕量級鎖
    lock->set_displaced_header(mark); // 保存Mark Word到鎖記錄
    if (Atomic::cmpxchg((markOop)lock, obj->mark_addr(), mark) == mark) {
      return; // 輕量級鎖成功
    }
  }

  // 升級到重量級鎖
  ObjectMonitor* monitor = inflate_monitor(obj, self);
  monitor->enter(self); // 進入Monitor
}

關(guān)鍵點解釋

  1. 無鎖到偏向鎖
    • 檢查Mark Word是否為無鎖(is_neutral())。
    • 用CAS(cmpxchg)將線程ID寫入Mark Word。
  2. 偏向鎖到輕量級鎖
    • 如果有競爭,撤銷偏向鎖(biased_to失敗)。
    • 將Mark Word替換為鎖記錄指針,保存原Mark Word到鎖記錄。
  3. 輕量級鎖到重量級鎖
    • 如果競爭加劇,創(chuàng)建Monitor(inflate_monitor)。
    • Mark Word指向Monitor,進入操作系統(tǒng)級鎖。

4.4 Monitor與對象頭的交互

重量級鎖依賴ObjectMonitor類(objectMonitor.hpp),Mark Word存儲Monitor指針:

class ObjectMonitor {
private:
  Thread* _owner; // 持有鎖的線程
  markOop _header; // 保存原來的Mark Word
  // ...
};
  • 當鎖升級為重量級鎖,Mark Word指向ObjectMonitor實例。
  • 釋放鎖時,ObjectMonitor將保存的 _header(原Mark Word)恢復到對象頭。

五、對象頭的內(nèi)存開銷和優(yōu)化

5.1 內(nèi)存開銷

在64位JVM中,對象頭的典型大?。?/p>

  • 普通對象:8字節(jié)(Mark Word)+ 8字節(jié)(Class Metadata Address)= 16字節(jié)。
  • 數(shù)組對象:16字節(jié) + 4字節(jié)(Array Length)= 20字節(jié)。

這意味著即使一個空對象(無字段)也有16字節(jié)的開銷,主要來自對象頭。

5.2 指針壓縮

為了減少內(nèi)存開銷,HotSpot JVM支持指針壓縮(-XX:+UseCompressedOops):

  • 將64位指針壓縮為32位(通過偏移編碼)。
  • 壓縮后,對象頭大小變?yōu)椋?ul>
  • 普通對象:8字節(jié)(Mark Word)+ 4字節(jié)(壓縮的Class Metadata Address)= 12字節(jié)。
  • 數(shù)組對象:12字節(jié) + 4字節(jié)(Array Length)= 16字節(jié)。

通俗解釋

  • 指針壓縮就像把“詳細地址”的省市縣簡化成“郵編”,節(jié)省空間。

5.3 鎖優(yōu)化

對象頭的鎖狀態(tài)切換(偏向鎖 → 輕量級鎖 → 重量級鎖)是JVM的性能優(yōu)化:

  • 偏向鎖:適合單線程場景,Mark Word直接記錄線程ID,獲取鎖幾乎無開銷。
  • 輕量級鎖:適合低競爭場景,用CAS操作鎖記錄,減少系統(tǒng)調(diào)用。
  • 重量級鎖:適合高競爭場景,依賴操作系統(tǒng)Mutex,但開銷大。

六、完整流程

  1. 對象頭的定義

    • 每個Java對象在內(nèi)存中包含對象頭,分為Mark Word、Class Metadata Address、Array Length(可選)。
    • Mark Word 是動態(tài)部分,存儲鎖狀態(tài)、哈希碼、GC年齡等。
  2. 對象頭的作用

    • 鎖機制:通過Mark Word實現(xiàn)synchronized的偏向鎖、輕量級鎖、重量級鎖。
    • 垃圾回收:記錄分代年齡,支持分代GC。
    • 類型信息:指向類元數(shù)據(jù),確定對象類型。
    • 哈希碼:存儲hashCode()值。
  3. 底層實現(xiàn)

    • Mark Word 由markOop類管理,通過位運算提取信息。
    • 鎖狀態(tài)切換由synchronizer.cpp實現(xiàn),涉及CAS和Monitor。
    • 對象頭與JVM的內(nèi)存管理和線程調(diào)度緊密協(xié)作。
  4. 內(nèi)存優(yōu)化

    • 指針壓縮減少對象頭大小(16字節(jié) → 12字節(jié))。
    • 鎖優(yōu)化(偏向鎖、輕量級鎖)降低鎖開銷。

七、通俗總結(jié)

  • 對象頭是什么?它是對象的“身份證”,記錄鎖狀態(tài)、類型信息、年齡等。
  • 怎么工作?Mark Word 像一個多功能顯示屏,根據(jù)對象狀態(tài)切換顯示內(nèi)容(鎖、哈希碼等)。
  • 為什么重要?沒有對象頭,JVM無法實現(xiàn)鎖、垃圾回收等核心功能。
  • 底層實現(xiàn)?通過HotSpot JVM的C++代碼(markOop、synchronizer)管理,依賴位運算和操作系統(tǒng)支持。

生活化比喻

  • 對象頭就像一個智能門牌,平時顯示房間號(類型信息)、住戶ID(鎖狀態(tài))、房屋年齡(GC年齡)。
  • 當有人敲門(線程訪問),門牌會切換顯示“誰能進”(鎖信息),還能記錄“敲門次數(shù)”(哈希碼)。

八、擴展閱讀

  1. 源碼推薦
    • HotSpot JVM:markOop.hpp(Mark Word定義)、synchronizer.cpp(鎖邏輯)。
    • 相關(guān)類:oop.hpp(對象布局)、objectMonitor.hpp(Monitor實現(xiàn))。
  2. 工具
    • 用jmap -histo查看對象內(nèi)存占用,分析對象頭開銷。
    • 用jol(Java Object Layout)庫查看對象頭結(jié)構(gòu)。
  3. 書籍
    • 《深入理解Java虛擬機》(周志明):深入講解JVM內(nèi)存和對象頭。
    • 《Java并發(fā)編程實戰(zhàn)》:結(jié)合鎖機制理解對象頭。

到此這篇關(guān)于Java的對象頭原理與源碼超詳細講解的文章就介紹到這了,更多相關(guān)Java對象頭原理詳解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java語言實現(xiàn)簡單FTP軟件 FTP協(xié)議分析(1)

    Java語言實現(xiàn)簡單FTP軟件 FTP協(xié)議分析(1)

    這篇文章主要介紹了Java語言實現(xiàn)簡單FTP軟件的第一篇,針對FTP協(xié)議進行分析,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Effective Java (異常處理)

    Effective Java (異常處理)

    Effective Java (異常處理),需要的朋友可以參考一下
    2013-02-02
  • Springboot?maven項目配置文件覆蓋問題的處理

    Springboot?maven項目配置文件覆蓋問題的處理

    這篇文章主要介紹了Springboot?maven項目配置文件覆蓋問題的處理方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 完美解決idea突然間很卡的問題

    完美解決idea突然間很卡的問題

    這篇文章主要介紹了完美解決idea突然間很卡的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java Stream 流的使用過程解析

    Java Stream 流的使用過程解析

    這篇文章主要介紹了Java Stream 流的使用過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • Java數(shù)據(jù)結(jié)構(gòu)專題解析之棧和隊列的實現(xiàn)

    Java數(shù)據(jù)結(jié)構(gòu)專題解析之棧和隊列的實現(xiàn)

    從數(shù)據(jù)結(jié)構(gòu)的定義看,棧和隊列也是一種線性表。其不同之處在于棧和隊列的相關(guān)運算具有特殊性,只是線性表相關(guān)運算的一個子集。更準確的說,一般線性表的插入、刪除運算不受限制,而棧和隊列上的插入刪除運算均受某種特殊限制。因此,棧和隊列也稱作操作受限的線性表
    2021-10-10
  • 查看import的類是出自哪個jar包的方法

    查看import的類是出自哪個jar包的方法

    下面小編就為大家?guī)硪黄榭磇mport的類是出自哪個jar包的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • Java中數(shù)組容器(ArrayList)設(shè)的計與實現(xiàn)

    Java中數(shù)組容器(ArrayList)設(shè)的計與實現(xiàn)

    本篇文章主要跟大家介紹我們最常使用的一種容器ArrayList、Vector的原理,并且自己使用Java實現(xiàn)自己的數(shù)組容器MyArrayList,讓自己寫的容器能像ArrayList那樣工作,感興趣的可以了解一下
    2022-07-07
  • Springboot配置文件相關(guān)說明解析

    Springboot配置文件相關(guān)說明解析

    這篇文章主要介紹了Springboot配置文件相關(guān)說明解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • SpringBoot?+?Redis如何解決重復提交問題(冪等)

    SpringBoot?+?Redis如何解決重復提交問題(冪等)

    在開發(fā)中,一個對外暴露的接口可能會面臨瞬間的大量重復請求,本文就介紹了SpringBoot + Redis如何解決重復提交問題,具有一定的參考價值,感興趣的可以了解一下
    2021-12-12

最新評論