在Java虚拟机中,每一个Java对象都由标记字段(markword)、类型指针(class pointer)、实例数据(instance data)和内存对齐(padding)构成,数组对象还有数组长度(length,4字节)。markword里主要存储虚拟机有关该对象的运行数据,如hashcode、gc年龄和锁信息;class pointer则是表示该对象属于什么class;instance data则是对象的成员属性;padding则是虚拟机的自动对齐,保证一个对象所占用的内存字节数是8的倍数。
使用JOL(Java Object Layout)工具可以输出Java对象的内存布局情况,所需mave依赖如下所示:
<dependencies>
<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
</dependencies>
示例程序
public class JavaObjectLayout {
private int i;
private String a;
public static void main(String[] args) {
JavaObjectLayout javaObjectLayout = new JavaObjectLayout();
System.out.println(ClassLayout.parseInstance(javaObjectLayout).toPrintable());
}
}
JVM默认设置下输出结果:
JavaObjectLayout object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
12 4 int JavaObjectLayout.i 0
16 4 java.lang.String JavaObjectLayout.a null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
为了尽量较少对象的内存使用量,64位Java虚拟机引入了压缩指针的概念(对应虚拟机选项-XX:+UseCompressedOops,-XX:+UseCompressedClassPointers,默认开启),将堆中原本64位的Java对象指针和类型指针压缩成32位的。这样一来,对象头中的类型指针也会被压缩成32位,使得对象头的大小从16字节降至12字节。当然,压缩指针不仅可以作用于对象头的类型指针,还可以作用于引用类型的字段,以及引用类型数组。
去除压缩指针设置后输出结果:
JavaObjectLayout object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 28 e0 4c 04 (00101000 11100000 01001100 00000100) (72146984)
12 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
16 4 int JavaObjectLayout.i 0
20 4 (alignment/padding gap)
24 8 java.lang.String JavaObjectLayout.a null
Instance size: 32 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total