天天看點

java對象頭markword_從Java對象布局markword看syncronized的本質

java對象頭markword_從Java對象布局markword看syncronized的本質

在HotSpot中,記憶體裡的一個Java對象分為三部分:對象頭,執行個體資料,對齊。其中

普通對象布局:

markword

8Bytes

用于标記鎖資訊、GC資訊、IdentityHashCode等

Class Pointer 類指針

4Bytes

用于标記該對象是哪個Class的執行個體

開啟記憶體壓縮(-XX:+UseCompressedClassPointer)後為4位元組,不開啟記憶體壓縮為8個位元組(下面有例子)

成員變量

視成員變量的類型和數量而定

如果沒有成員變量,則這一塊為空

Padding 對齊

視上述位元組而定

一個對象占用的位元組數必須是8的倍數,不足的用padding對齊

數組對象布局:

markword

8Bytes

用于标記鎖資訊、GC資訊、IdentityHashCode等

Class Pointer

類指針

4Bytes

用于标記該對象是哪個Class的執行個體

開啟記憶體壓縮(-XX:+UseCompressedClassPointer)後為4位元組,

不開啟記憶體壓縮為8個位元組

數組長度

4Bytes

标記數組有多少個元素

數組内容

根據數組類型m和長度n而定,長度為m*n

如果元素為基本類型,比如byte/boolean/short/char/int/long/double,則m為對應的長度;如果元素為數組,m是4位元組的引用

如果數組長度為0,這一塊為空

Padding 對齊

視上述位元組而定

一個對象占用的位元組數必須是8的倍數,不足的用padding對齊

可以通過以下工具來檢視對象的布局:JOL=Java Object Layout。

org.openjdk.jol

jol-core

0.10

先看看普通對象的布局:編寫代碼:

import org.openjdk.jol.info.ClassLayout;

public class JavaObjectLayout {

public static void main(String[] args) {

System.out.println("------------Object---------------");

Object o = new Object();

String s = ClassLayout.parseInstance(o).toPrintable();

System.out.println(s);

}

}

java對象頭markword_從Java對象布局markword看syncronized的本質

可以看到,前12個位元組都是object header,其中前8個位元組(前兩行)是markword,後4個位元組(第三行)是對象指針。由于Object類沒有成員變量,這塊為空,是以最後4個位元組(第四行)是對齊。

如果執行的時候使用JVM參數-XX:-UseCompressedClassPointers關閉類指針壓縮,則class pointer将占用8位元組:

java對象頭markword_從Java對象布局markword看syncronized的本質
java對象頭markword_從Java對象布局markword看syncronized的本質

同理可以檢視數組對象的布局:

import org.openjdk.jol.info.ClassLayout;

public class JavaObjectLayout {

public static void main(String[] args) {

System.out.println("------------Object[2]---------------");

Object[] os = new Object[2];

System.out.println(ClassLayout.parseInstance(os).toPrintable());

}

}

java對象頭markword_從Java對象布局markword看syncronized的本質

可以看到,從偏移量12開始,數組長度為4位元組,值為2,然後16位元組開始,為2x4=8位元組的數組内容(每個Object的引用長度為4位元組)。

現在,我們去掉JVM參數,并用syncronized對該對象加鎖,看看markword有什麼變化:

import org.openjdk.jol.info.ClassLayout;

public class JavaObjectLayout {

public static void main(String[] args) {

System.out.println("------------Object---------------");

Object o = new Object();

synchronized (o) {

System.out.println(ClassLayout.parseInstance(o).toPrintable());

}

}

}

java對象頭markword_從Java對象布局markword看syncronized的本質

可以看到,markword的前4個位元組的内容發生了變化。是以,syncronized加鎖的本質,是修改了該對象的markword。