1 Java对象的内存布局
在HotSpot虚拟机里,对象在堆内存的存储布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding,保证对象始终为8字节的倍数)。
1.1 对象头
对象头分为对象标记(markOop)和类元信息(klassOop),类元信息存储的是指向该对象类元数据(klass)的首地址。如果是数组对象的话,对象头还会包含数组长度。
- MarkWord:记录了对象和锁有关的信息,在64位JVM的大小是64bit。当这个对象被synchronized关键字当成同步锁时,围绕这个锁的一系列操作都和Mark Word有关,下面是64位JVM的MarkWord在不同锁状态下对应的不同内容,最后2bit是锁标记位,用于表示不同的锁状态。
- klass类元信息:又称类型指针,在64位JVM是64bit(忽略压缩指针的影响)。对象指向它的类元数据(存放在方法区)的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
1.2 实例数据
存放类的属性数据信息,包括父类的属性信息。
1.3 对齐填充
因为JVM要求java的对象占的内存大小应该是8字节的倍数,所以后面有几个字节用于把对象的大小补齐至8字节的倍数,没有特别的功能。
1.4 JOL代码验证(64位JVM)
引入maven依赖:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
class Customer {
int id;
boolean flag = false;
}
测试Customer类:
public class Juc118_Jol {
public static void main(String[] args) {
Customer customer = new Customer();
System.out.println(ClassLayout.parseInstance(customer).toPrintable());
}
}
打印结果如下:
MarkWord:4字节(0-7)
klass类元指针:8-11,这里类型指针占4字节是由于压缩指针的缘故
实例数据:id 4个字节,flag 1个字节
对齐填充:为了17字节补齐到24字节(8的倍数)的7字节的对齐填充
1.5 压缩指针
java默认开启了压缩指针(-XX:+UseCompressedClassPointers),以节约空间。如果不想要压缩指针,配置如下即可: