一.类加载检查
遇到new指令->看在常量池能否定位到这个参数的类引用和看这个类是否已经被加载,解析和初始化过。
二.分配内存
1.两种分配方式:
- 指针碰撞:java堆中内存是所有用过和没用过的内存分开放的,中间用指针分界,那么分配时就把指针向空闲区挪。(Serial,ParNew)
- 空闲列表:java堆中内存是所有用过和没用过的内存分开放的一起放的,用列表记录那些内存块可用,分配时在列表上找够大的内存,并更新列表(CMS)
注意:分配方式跟你用的垃圾收集器是否有空间压缩整理功能(compact)有关
2.内存分配并发问题(eg:给A分配内存指针还没来得及修改,B也要修改指针),线程不安全了,采用两种方式来保证线程安全:
- CAS+失败重试: CAS 是乐观锁的一种实现方式。(乐观锁:每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。)虚拟机采用 CAS 失败重试来保证更新操作的原子性。
- TLAB: JVM在给线程中的对象分配内存时,首先在 TLAB分配,当对象大于TLAB中的剩余内存或TLAB的内存已用尽时,再采用上述的CAS进行内存分配
三.初始化零值
虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),保证了对象的实例字段在 Java 代码中可以不赋初始值就直接使用
四.设置对象头
虚拟机要对对象进行必要的设置,将这个对象是那个类的实 例、如何才能找到类的元数据信息、对象的哈希吗、对象的 GC 分代年龄等这些信息存放在对象头中。 另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。
五.执行init方法
执行前所有字段默认为0,执行后对象初始化