-
1.类加载检查
当虚拟机遇到一条new指令时,首先去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,需要先执行相应的类加载过程。 -
2.分配内存
在类加载检查通过后,接下来虚拟机会为新生的对象分配内存。对象所需内存的大小在类加载完成后便可以确定,为对象分配内存就是在堆中划分出一块确定大小的区域分配给对象。
分配内存的方式:指针碰撞和空闲列表。选择哪种分配方式,由Java堆是否规整决定,Java堆是否规整由所采用的垃圾收集器是否带有压缩整理功能决定。
指针碰撞:
适用场景:内存规整的情况下。
原理:使用过的内存被全部整合到一端,没用过的内存放在另一端,中间有一个分界值指针,只需要将分界值指针向没有使用过的内存移动对象内存大小的位置即可。
空闲列表:
适用场景:内存不规整的情况。
原理:虚拟机会维护一个列表,该列表中会记录那些内存块是可用的,在分配的时候,找一块足够大的内存来划分给对象实例,后更新到列表记录。
-
3.初始化零值
内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一步保证了对象的实例字段在Java代码中可以不赋任何初始值就可以使用,程序能访问到这些字段的数据类型所对应的零值。 -
4.设置对象头
在初始化零值完成之后,虚拟机要对对象进行必要的设置,例如这个对象时哪个类的实例、如何才能找到类的元数据信息、对象的hashCode,对象的GC分代年龄信息等。这些信息放在对象头中。另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。 -
5.执行init方法
在完成上面的几个过程之后,从虚拟机的角度来看,一个新的对象已经产生了。但从Java的角度来看,对象创建才刚刚开始,方法还没执行,所有的字段都还为零。所以一般来说,执行 new 指令之后会接着执行 方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。