在虚拟机中,Java对象在内存中的布局可以分为三块:
- 对象头(Header) :包含 markword 标记字段和类型指针,32 位上大小是 8 个字节,64 位 16 个字节,
- 实例数据(Instance Data):包含了对象的所有成员变量,其大小由各个成员变量的大小决定,HotSpot虚拟机的默认分配策略中,宽度相等的字段总是被分配到一起存放,如
long
和double
,short
和char
,byte
和boolean
等 - 对齐填充(Padding) :占位符的作用,HotSpot 虚拟机要求对象的大小必须是 8 字节的整数倍(因为对象头部分被精心设计成是 8 字节的倍数(1倍或2倍)),这部分并不是必然存在的,如果对象实例数据没有对齐的话,就需要通过对齐填充进行补全。
对象头又包括:
- markword 标记字段(哈希码、GC分代年龄、锁状态等,32位上是4字节,64位8字节)
- 类型指针,指向对象的类型元数据的指针,JVM 通过这个指针来确定这个对象是属于哪个类的实例,32 位 4 字节,64 位开启指针压缩 4 字节,否则 8 字节,jdk 1.8 默认开启指针压缩后为 4 字节
- 数组长度,如果对象是一个数组对象, 那在对象头中还必须有一块数据用于记录数组长度。 4 字节
对于 64 位上的一个空对象:
也就是说,在 64 位系统上,不开启指针压缩的情况下,一个空对象也要占用 16 字节的大小,而如果这个对象是数组对象,还要额外占用 4 字节,即 20 字节。
所以,在开发中应当尽量避免使用包装类型和枚举类型作为参数类型设计,使用包装类型除了拆装箱的开销外,在数据规模较大的情况下,还有可能占用较大的内存或者造成内存抖动。