(未完待续)从JVM角度分析 new 一个对象的详细过程

280 阅读2分钟

Prerequisite:内存布局和类加载流程

要理解一个对象的创建过程,需要从运行时数据区进行分析,首先需要对JVM运行时数据区布局有深入的理解,同时掌握类加载过程中各个阶段的行为。

Tip:实践结合理论

梳理new 对象的过程,也是间接从实践的角度去复习了JVM 运行时数据布局和类加载流程两个大主题,后者以前者为基础。

简化流程解析

当虚拟机遇到一个 new 指令时:

1、在常量池中检查
在常量池中检查是能找到一个当前类的符号引用,并检查该符号引用代表的类是否已经被加载、解析和初始化过。

2、类加载检查通过

3、在堆中为这个类的对象分配确定大小的内存块,内存大小在类加载完成之后,就已经确定下来。

4、JVM 将分配到的内存空间都初始化为零(不包括对象头)。

5、设置对象头。对象头中存储了该对象是哪个类的实例等信息。

6、执行 init 方法(否则所有字段还为零值),把对象按照程序员的意愿进行初始化。

简化流程示意图

实例分析

代码编译完,有TestClient.class 和 Person.class 两个类文件。 JVM 读取 main 方法入口,发现 Person p = new Person(); 这个需要创建对象的语句所对应的字节码指令,执行如下操作:

1、加载 Person.class 文件到方法区,同事加载 Person 类中的 static 属性 2、在 main 方法所在的栈区分配引用 p 3、在堆中开辟空间存放Person 类,但是不进行初始化操作 4、初始化数据字段 5、将引用 p 指向 Java 中新开辟的 Person 类


对象的内存布局

对象在堆内存中,存储布局分为三部分:

对象头(Object Header)

实例对象(Instance Data)

对齐填充(Padding)

对象头

对象头包含2部分信息:

1、存储对象自身的运行时数据:哈希吗、GC分代年龄、锁定态标识、线程持有锁等

2、指针类型:即对象指向它的类元数据的指针。JVM 通过这个指针类确定这个对象属于哪个类的实例。