资料来源于深入理解Java虚拟机:JVM高级特性与最佳实践 周志明著
1.常量池中定位类的符号引用
若常量池中存在new指令的参数,表示该类已经被加载、解析和初始化过,否则,先执行类的加载过程
2.堆中空间分配
在类加载检查通过后,在堆中为对象分配内存。分配方式有两种,取决于堆内存区域是否规整。
- 指针碰撞。在新生代一般采用的是Serial,ParNew等垃圾收集器,使用的是标记复制算法,因此内存规整,用过的在一边,空闲的在另一边。分配内存时将本来指向中间的指针,向空闲空间挪动一段与大小相等的距离
- 空闲列表。在老年代中使用CMS垃圾收集器,使用标记清除算法。所以需要维护一个列表,记录哪些内存块可用,分配的时候遍历列表找到一块足够大的空间划分给对象
分配时的并发安全
两种解决方案:
- 1.JVM采用CAS失败重试的方式保证更新操作的原子性从而保证分配时的并发安全
- 2.使用TLAB(本地线程分配缓冲)。在堆中为每个线程划分出一小块内存,哪个线程创建对象需要分配内存,就在自己的TLAB上分配。若TLAB用完,需要分配新的TLAB时,需要进行同步锁定
通过 -XX:+UseTLAB 来启用
3.对象属性初始化
内存分配完成后,虚拟机将对象中的属性初始化为对应的零值
4.设置对象头
对对象头进行设置,包含:对象是哪个类的实例,如何找到类的元数据信息,对象的哈希吗,对象的GC分代年龄等。对象头会根据当前虚拟机运行的状态而变成不同的数据
5.执行构造方法
以上步骤完成后,在虚拟机的视角对象已经产生了,但对于Java程序员,对象创建才刚刚开始,接着需要执行对象的构造函数方法
HotSpot解释器代码片段