从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。 

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

先看看普通对象的布局:编写代码:

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看syncronized的本质
可以看到,前12个字节都是object header,其中前8个字节(前两行)是markword,后4个字节(第三行)是对象指针。由于Object类没有成员变量,这块为空,因此最后4个字节(第四行)是对齐。

如果执行的时候使用JVM参数-XX:-UseCompressedClassPointers关闭类指针压缩,则class pointer将占用8字节:从Java对象布局markword看syncronized的本质

从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看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看syncronized的本质
可以看到,markword的前4个字节的内容发生了变化。因此,syncronized加锁的本质,是修改了该对象的markword。

 推荐:也组词

上一篇:探究Jvm源码实现-MarkWord


下一篇:java对象结构 对象头 Markword