java併發編程(五)Java對象頭 一、對象頭 二、Mark Word簡介

在我們學習synchronized的原理之前,必須要先學習下java的對象頭,這有助於我們理解synchronized。

一、對象頭

1.1 對象頭介紹

java對象分爲對象頭,對象體,對齊字段,如下所示:

我們下面主要關注對象頭的內容:

對象頭 = Mark Word + Klass Word

如果是數組對象則:

對象頭 = Mark Word + Klass Word + 數組長度

Klass Word:存儲一個地址,長度取決於系統位數,32位和64位,該地址指向方法區中類的元數據信息。

常見的虛擬機分爲32位和64位,則其對象頭也會不同:

在32位系統中,Mark Word = 4 bytes = 32 bits,對象頭 = 8 bytes = 64 bits;
在64位系統中,Mark Word = 8 bytes = 64 bits ,對象頭 = 16 bytes = 128bits;

bytes 是字節,bits 是位。

  • 32位虛擬機虛擬機普通對象頭
|-----------------------------------------------------------|
|                    Object Header (64 bits)                |
|---------------------------------|-------------------------|
|             Mark Word (32 bits) | Klass Word (32 bits)    |
|---------------------------------|-------------------------|
  • 32位虛擬機虛擬機數組對象頭
|---------------------------------------------------------------------------------|
|                                  Object Header (96 bits)                        |
|--------------------------------|-----------------------|------------------------|
|       Mark Word(32bits)        | Klass Word(32bits)    | array length(32bits)   |
|--------------------------------|-----------------------|------------------------|
  • 32位虛擬機Mark Word
|----------------------------------------------------------------------------------------------|
|                       Mark Word(32bits)                                 |        State       |
|----------------------------------------------------------------------------------------------|
|     hashcode:25                      | age:4 | biased_lock:0 |  lock:01 |      Nomal         |
|----------------------------------------------------------------------------------------------|
|     thread:23              | epoch:2 | age:4 | biased_lock:1 |  lock:01 |      Biased        |
|----------------------------------------------------------------------------------------------|
|     ptr_to_lock_record:30                                    |  lock:00 | Lightweight Locked |
|----------------------------------------------------------------------------------------------|
|     ptr_to_heavyweight_monitor:30                            |  lock:10 | Heavyweight Locked |
|----------------------------------------------------------------------------------------------|
|                                                              |  lock:11 |    Marked for GC   |
|----------------------------------------------------------------------------------------------|
  • 64位虛擬機虛擬機普通對象頭
|--------------------------------------------------------------------------------------------|
|                                 Object Header(128bits)                                     |
|--------------------------------------------------------------------------------------------|
|                    Mark Word(64bits)             |         Klass Word(64bits)              | 
|--------------------------------------------------------------------------------------------|
  • 64位虛擬機虛擬機數組對象頭
|---------------------------------------------------------------------------------------------------------|
|                                  Object Header (192 bits)                                               |
|--------------------------------|-----------------------|------------------------|-----------------------|
|       Mark Word(64bits)        | Klass Word(64bits)    | array length(32bits)   |  alignment(32bits)    |
|--------------------------------|-----------------------|------------------------|-----------------------|

在數組對象當中,有一個對齊長度(alignment/padding gap)是8字節,但是其中是包含數組長度4個字節,所以對齊字節長度也是4,具體可以看我下一小節的演示。

  • 64位虛擬機Mark Word
|----------------------------------------------------------------------------------------------|
|                                   Mark Word(64bits)                     |      State         |
|----------------------------------------------------------------------------------------------|
|    unused:25|identity_hashcode:31|unused:1|age:4|biase_lock:0| lock:01  |      Nomal         |
|----------------------------------------------------------------------------------------------|
|    thread:54|      epoch:2       |unused:1|age:4|biase_lock:1| lock:01  |      Biased        |
|----------------------------------------------------------------------------------------------|
|                        ptr_to_lock_record:62                 | lock:00  | Lightweight Locked |
|----------------------------------------------------------------------------------------------|
|                       ptr_to_heavyweight_monitor:62          | lock:10  | Heavyweight Locked |
|----------------------------------------------------------------------------------------------|
|                                                              | lock:11  |    Marked for GC   |
|----------------------------------------------------------------------------------------------|

1.2 查看對象頭

引入下列依賴:

<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.16</version>
</dependency>

本文並沒有使用網上大家都在使用的0.10版本,因爲對比後我發現,新版本0.16更能清晰的體現對象頭的內容。同學們可以自行對比下。

首先聲明兩個JVM的參數:

  • -XX:-UseCompressedOops 關閉壓縮
  • -XX:+UseCompressedOops 開啓壓縮

我的是默認開啓的,所以需要使用-XX:-UseCompressedOops將其關閉。

下面會簡單模擬是普通對象和數組對象,我的電腦都是64位的,即參照64位虛擬機的結果。

給定一個空的Student對象:

public class Student {

}

測試類如下:

public class ObjectHeader {

    public static void main(String[] args) {
        //對象
        Student student = new Student();
        //數組
        String[] strings = new String[]{};
        // 打印jvm的具體參數
        System.out.println(VM.current().details());
        // 打印普通對象頭信息
        System.out.println(ClassLayout.parseInstance(student).toPrintable());
        // 打印數組對象頭信息
        System.out.println(ClassLayout.parseInstance(strings).toPrintable());
    }
}

結果如下:

Connected to the target VM, address: '127.0.0.1:63960', transport: 'socket'
# Running 64-bit HotSpot VM.
# Objects are 8 bytes aligned.
# Field sizes by type: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

com.cloud.bssp.thread.objectheader.Student object internals:
OFF  SZ   TYPE DESCRIPTION               VALUE
  0   8        (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   8        (object header: class)    0x000000001c2b1cd0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

[Ljava.lang.String; object internals:
OFF  SZ               TYPE DESCRIPTION               VALUE
  0   8                    (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   8                    (object header: class)    0x000000001bfa4268
 16   4                    (array length)            0
 16   8                    (alignment/padding gap)   
 24   0   java.lang.String String;.<elements>        N/A
Instance size: 24 bytes
Space losses: 8 bytes internal + 0 bytes external = 8 bytes total

下面我們逐行進行講解:

  • JVM參數
  // 64位虛擬機
  Running 64-bit HotSpot VM.
  //  按照8個字節對齊,即忽略第一個8字節
  Objects are 8 bytes aligned.
  // 忽略8字節後,餘下的其實都是基本類型所佔的字節:boolean,byte,char,short,int,float,long,double的大小
  Field sizes by type: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
  // 數組中元素所佔字節,同上面
  >Array element sizes: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
  • 普通對象 com.cloud.bssp.thread.objectheader.Student
// 很明顯,下面是mark word的大小,8個字節,64bits
object header: mark 
// 如下是klass word的大小,8個字節,64bits
object header: class
// 實例大小是16字節。
Instance size: 16 bytes
//空間損失,是否有對其字節,內部對齊和外部對齊
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
  • 數組對象 [Ljava.lang.String; object
// 很明顯,下面是mark word的大小,8個字節,64bits
object header: mark 
// 如下是klass word的大小,8個字節,64bits
object header: class
// 數組長度
array length
// 內部的對齊字節大小
alignment/padding gap
// 空數組
java.lang.String String;.<elements>        N/A
// 實例大小是24
Instance size: 24 bytes
//空間損失,8個是內部對齊字節,其中包含字節的長度4,也就是補齊了4個
Space losses: 8 bytes internal + 0 bytes external = 8 bytes total

二、Mark Word簡介

這一節簡單介紹小Mark Word當中的參數都是什麼意思,以64位虛擬機介紹。

|----------------------------------------------------------------------------------------------|
|                                   Mark Word(64bits)                     |      State         |
|----------------------------------------------------------------------------------------------|
|    unused:25|identity_hashcode:31|unused:1|age:4|biase_lock:0| lock:01  |      Nomal         |
|----------------------------------------------------------------------------------------------|
|    thread:54|      epoch:2       |unused:1|age:4|biase_lock:1| lock:01  |      Biased        |
|----------------------------------------------------------------------------------------------|
|                        ptr_to_lock_record:62                 | lock:00  | Lightweight Locked |
|----------------------------------------------------------------------------------------------|
|                       ptr_to_heavyweight_monitor:62          | lock:10  | Heavyweight Locked |
|----------------------------------------------------------------------------------------------|
|                                                              | lock:11  |    Marked for GC   |
|----------------------------------------------------------------------------------------------|

先看state這一列,由上至下分別代表synchronized鎖的狀態:無鎖,偏向鎖,輕量級鎖,重量級鎖,GC。每個鎖的含義將在下一篇文章重點講解。

下面以行爲單位,由上至下查看:

  • Nomal (無鎖)
    unused:未使用25位
    identity_hashcode:31位的對象標識hashCode
    unused:未使用1位
    age:4位的Java對象GC回收年齡。
    biase_lock:1位偏向鎖標記,0未啓用
    locked:2位鎖狀態標誌位,配合biased_lock表示java對象各階段不同鎖狀態。

  • Biased(偏向鎖)
    thread:54位的持有偏向鎖的線程id
    epoch:偏向鎖的時間戳
    unused:未使用1位
    age:4位的Java對象GC回收年齡。
    biase_lock:1位偏向鎖標記,1啓用
    locked:2位鎖狀態標誌位,配合biased_lock表示java對象各階段不同鎖狀態。

  • Lightweight Locked(輕量級鎖)
    ptr_to_lock_record:輕量級鎖狀態下,指向棧中鎖記錄的指針。
    locked:2位鎖狀態標誌位,00表示輕量級鎖。

  • Heavyweight Locked(重量級鎖)
    ptr_to_heavyweight_monitor:重量級鎖狀態下,指向Monitor(監視器或管程,下一篇文章講解)的指針。
    locked:2位鎖狀態標誌位,10表示輕量級鎖。

  • Marked for GC(GC標記)
    locked:2位鎖狀態標誌位,11表示被標記爲垃圾回收。


關於對象頭的內容,目前就介紹這麼多,下一篇文章會講解synchronized的相關內容和原理。有用的話給個關注,點贊吧!!

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