在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);
}
}
可以看到,前12个字节都是object header,其中前8个字节(前两行)是markword,后4个字节(第三行)是对象指针。由于Object类没有成员变量,这块为空,因此最后4个字节(第四行)是对齐。
如果执行的时候使用JVM参数-XX:-UseCompressedClassPointers关闭类指针压缩,则class pointer将占用8字节:
同理可以查看数组对象的布局:
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());
}
}
可以看到,从偏移量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());
}
}
}
可以看到,markword的前4个字节的内容发生了变化。因此,syncronized加锁的本质,是修改了该对象的markword。
推荐:也组词