1. 类加载检查
当java虚拟机遇到一条new指令后,会先进行类加载检查的处理,即检查指令的参数是否在常量池中定位到一个类的符号引用,然后检查符号引用的类是否被加载,解析或者初始化过,若没有则首先执行类加载过程,若有进行下一步
2.为新生对象分配内存
对象所需的内存大小在类加载完毕就已经确定了,为对象分配内存空间就是在堆中划分出一段确定大小的内存块,分为两种划分方式
1. 指针碰撞
假设堆空间中空间布局是井然有序的,已分配空间和空闲空间划分如下图
那么分配对象空间仅仅是将指针向空闲空间移动一段与对象大小相等的距离,这种分配 方式叫做指针碰撞
2. 空闲列表
而已分配空间和空闲空间还存在杂糅的空间分配状态,如下图
这时指针就难以再适用于此类堆空间分布,于是虚拟机就采取维护列表的方式来进行堆空间管理,列表记录了哪些内存块是可用的,在分配的时候在列表中找到一块足够大的空间分配给对象实例,同时再更新列表信息,这种方式叫做空闲列表
附注:选择哪种对分配方式是由java堆是否界限分明决定的,而java堆界限分明是由GC器是否带有空间压缩整理能力决定的,系统采用指针碰撞既简单又高效,而使用CMS这种基于清除(Sweep)算法的收集器的时候,理论上只能采取较为复杂的空闲列表来实现
3. 内存空间的初始化
内存空间分配完成后,虚拟机必须将分配的空间初始化为零(不包含对象头),如果使用TLAB的话这一项任务可以提前至TLAB分配时顺便完成,例如是哪一个对象的实例,对象的哈希码,对象的GC分代年龄等信息,这些都存放在对象头之中
4.人为的处理对象
似乎现在我们的对象已经由虚拟机创建完成了,从虚拟机的视角来看,一个对象就此诞生了,但是从java程序来看并不是这样,对象的创建才刚刚开始---构造函数,即Class文件内的<init>()方法还没有执行,所有的字段都默认为零值,对象需要的其他资源和状态信息也没有按照预定的意图构造好,new之后会执行<init>()方法,按照程序员的意愿对对象进行初始化,这样一个真正的对象才算构造了出来