- 对象的内存布局
- 对象头
- Mark World
- 类型指针
- 实例数据
- 对齐填充
- 实战
- 空的String对象:
- 非空的String对象
对象的内存布局本文的讨论都是基于 HotSpot 虚拟机
要知道一个类对象占用的内存,我们就必须要知道对象的内存布局。
对象在堆内存中的存储布局可以划分为三个部分: 对象头,实例数据,对齐填充
对象的对象头包括两类信息。第一类是存储对象自身的运行时数据,第二类是类型指针
Mark World存储对象自身的运行时数据,如 哈希码,GC分代年龄、锁状态标志、线程持有的锁等等。这部分的数据长度在32位虚拟机中为4个字节,在64位虚拟机中是8个字节,官方称之为 Mark Word
类型指针指向它的类型元数据的指针(指向它的Class对象的指针),大小是4个字节。Java虚拟机通过这个指针来确定该对象是哪个类的实例
实例数据实例数据部分是对象真正存储的有效信息,即我们在程序代码里面所定义的各种类型的字段内容。计算方式是累加,如下对象:
public class O {
private int o1;
private long o2
}
实例数据部分长度就是 int(4字节)+long(8字节)=12字节
对齐填充第三部分就是对齐填充。HotSpot虚拟机的自动内存管理要求对象起始地址必须是8字节的整数倍,换句话说就是任何对象的大小都必须是8字节的整数倍。如果对象大小没到8字节的整数倍,那就需要通过对齐填充来补全。
实战已经知道了对象的内存布局,我们就可以来尝试计算一个类对象占用的内存:
我们就来计算 String类的内存:
我们先来查看String类里面的实例数据有哪些;
@Stable private final byte[] value; private final byte coder; private int hash; // Default to 0 private boolean hashIsZero; // Default to false; private static final long serialVersionUID = -6849794470754667710L; static final boolean COMPACT_STRINGS;
可以得到实例数据部分的字节是 数组对象 + byte(1字节)+ int(4字节)+ boolean(1字节) + long(8字节) + Boolean(1字节)
那么数组对象也是一个对象,它的占用内存是 对象头(8字节)+ 引用(4字节)+ 记录长度的int(4字节)=16字节。
所以空的String对象占用内存是 8+16+1+4+1+8+1+ 1字节(字节填充)=40字节
非空的String对象非空的string对象比空的string对象只有在数组对象里的 实例数据部分变化了,其他都没变,
所以非空的String对象占用内存是 8+16+1+4+1+8+1+ 1字节(字节填充)=40+ n字节(n是byte数组的长度)



