一、创建对象的过程
ⅰ 先加载类:
- 加载:将class文件加载进内存,在堆中生成对应的Class对象,作为访问方法区中类信息的入;
- 链接:(验证:class文件是否符合要求、准备:静态变量赋初值、解析:符号引用变为直接引用);
- 初始化:静态变量赋值;
ⅱ 分配对象空间:(类加载之后,对象的大小就完全确定了)
ⅲ 初始化实例变量为0值;
ⅳ 对象的初始设置(设置对象的对象头,这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息);
ⅴ init方法初始化,就是对象的实例属性的赋值;
二、对象的内存布局
对象在内存中存储的布局可以分为 3 块区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)。
对象头
HotSpot 虚拟机的对象头包含两部分信息。
- 第一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
- 对象的另一部分类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例(并不是所有的虚拟机实现都必须在对象数据上保留类型指针,也就是说,查找对象的元数据信息并不一定要经过对象本身)。
如果对象是一个 Java 数组,那在对象头中还必须有一块用于记录数组长度的数据。
实例数据
实例数据部分是对象真正存储的有效信息,也是在程序代码中定义的各种类型的字段内容,无论从父类继承下来的,还是在子类中定义的,都需要记录起来。这部分的存储顺序会受虚拟机默认的分配策略参数和字段在 Java 源码中定义的顺序影响(相同宽度的字段总是被分配到一起)。
规则:
- 相同宽度的字段总是被分配在一起
- 父类中定义的变量会出现在子类之前
- 如果 CompactFields 参数为 true(默认true),子类的窄变量可能插入到父类变量的空隙
对齐填充
对齐填充部分并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于 HotSpot VM 的自动内存管理系统要求对象的起始地址必须是 8 字节的整数倍,也就是说,对象的大小必须是 8 字节的整数倍。而对象头部分正好是 8 字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。
我们通过一个简单的例子加深下理解:
public class PersonObject {
public static void main(String[] args) {
Person person = new Person();
}
}
public class Person {
int id = 1008;
String name;
Department department;
{
name = "匿名用户"; //name赋值为字符串常量
}
}
public class Department {
int id;
String name;
}

浙公网安备 33010602011771号