HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。
对象头(Object Header)
标记字段:存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等
类型指针:指向该对象的类类型指针则指向该对象的类
在不开启指针压缩,对象头在32位系统上占用8bytes,64位系统上占用16bytes。
在开启指针压缩,对象头在64位系统上占用12bytes。
实例数据(Instance Data)
基本类型 大小(bytes)
boolean 1
byte 1
short 2
char 2
int 4
float 4
long 8
double 8
reference类型在32位系统上每个占用4bytes, 在64位系统上每个占用8bytes。
对齐填充(Padding)
填充规则:HotSpot的对齐方式为8字节对齐。
(对象头 + 实例数据 + padding) % 8等于0且0 <= padding < 8
例子
public class User {
private long id;
private int age;
private String name;
private Work work;
}
分析一下这个对象的内存分析,64位操作系统,开启指针压缩,对齐填充为8个字节
首先是对象头为12个字节,long为8个字节,int为4个字节,String为引用类型4个字节,Work为引用类型4个字节,所以一共12+8+4+4+4=32个字节,刚好是8个字节的倍数,不需要对齐填充。
计算对象内存分布工具——JOL
pom.xml引入
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
User user = new User();
String s = ClassLayout.parseInstance(user).toPrintable();
System.out.println(s);
cn.commonstool.jol.User 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) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 int User.age 0
16 8 long User.id 0
24 4 java.lang.String User.name null
28 4 cn.commonstool.jol.Work User.work null
Instance size: 32 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total