一.类加载检查
二.分配内存
虚拟机为新生对象分配内存,对象所需内存大小在类加载完成后确定,从堆中分配
分配方式有两种:
- 指针碰撞
- 空闲列表
1.内存分配两种方式
- 指针碰撞
- 适合场景:堆内存规整(没有内存碎片)
- 原理:用过内存全部整合在一遍,没有用过的在另一边,中间有分界指针,向着没有用过的内存方向将该指针移动对象内存大小位置
- 使用该分配方式的GC收集器:Serial, ParNew
- 空闲列表:
- 适用场景:堆内存不规整
- 原理:虚拟机维护内存分配列表,会找到足够大小的内存块分配给实例对象
- 使用该分配方式的 GC 收集器:CMS
2.内存分配并发问题
- CAS+失败重试:CAS是乐观锁的一种实现方式,每次不加锁,如果冲突就重试直到成功为止
- TLAB:为每个线程预先在Eden区分配一块内存,JVM在给线程对象分配内存时,首先在TLAB分配,对象大于TLAB中的剩余内存时候,再采用CAS内存分配
三.初始化零值
虚拟机将分配到的内存空间初始化为零值
保证对象的实例字段在 Java 代码中可以不赋初始值就直接使用
四.设置对象头
虚拟机要对对象进行必要设置,例如这个对象是哪个类的实例,如何才能找到类的元数据信息,对象的哈希码,对象的GC分代年龄等信息,这些信息存在对象头中
五.执行init方法
执行构造方法,赋初值
对象内存布局
对象头
- 实例数据
- 对齐填充
对象头:
- 存储对象自身的运行数据(哈希码,GC分代年龄,锁状态标志)
- 类型指针,对象指向他的类元数据的指针,确定对象是哪个类的实例
六.对象访问的定位
句柄
直接指针
使用句柄,对象改变,局部变量表的reference不用改变
使用直接指针,对象改变,局部变量表的reference需要改变