对象内存中可以分为三块区域:对象头(Header),实例数据(Instance Data)和对齐填充(Padding),以64位操作系统为例(未开启指针压缩的情况)Java对象布局如下图所示:
以64位操作系统为例,new Object()占用大小分为两种情况:
未开启指针压缩 占用大小为:8(Mark Word)+8(Class Pointer)=16字节
开启了指针压缩(默认是开启的) 开启指针压缩后,Class Pointer会被压缩为4字节,最终大小为:8(Mark Word)+4(Class Pointer)+4(对齐填充)=16字节。
验证:
1、引入依赖
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
2、代码
public class HeapMemory {
public static void main(String[] args) {
Object obj = new Object();
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
3、输出结果
(1)指针压缩情况
(2)指针无压缩情况
4、配置指针压缩参数
-XX:+UseCompressedOops 开启指针压缩
-XX:-UseCompressedOops 关闭指针压缩
5、对象访问方式
(1)句柄访问
使用句柄访问的话,Java虚拟机会在堆内划分出一块内存来存储句柄池,那么对象当中存储的就是句柄地址,然后句柄池中才会存储对象实例数据和对象类型数据地址。
(2)直接指针访问(Hot Spot虚拟机采用的方式)
直接指针访问的话对象中就会直接存储对象类型数据。
6、句柄访问和直接指针访问对比
使用句柄访问的时候,会多了一次指针定位,但优点在于假如一个对象地址发生改变,那么只需要改变句柄池的指向就可以了,不需要修改reference对象内的指向,而如果使用直接指针访问,就还需要到局部变量表内修改reference指向。