一.类加载检查

遇到new指令---->指令参数在常量池中定位到这个类的符号引用---->是否被加载过。解析,初始化过

#JVM学习笔记(二)HotSpot 虚拟机对象创建_jvm

二.分配内存

虚拟机为新生对象分配内存,对象所需内存大小在类加载完成后确定,从堆中分配

分配方式有两种:

  • 指针碰撞
  • 空闲列表

1.内存分配两种方式

  • 指针碰撞
  • 适合场景:堆内存规整(没有内存碎片)
  • 原理:用过内存全部整合在一遍,没有用过的在另一边,中间有分界指针,向着没有用过的内存方向将该指针移动对象内存大小位置
  • 使用该分配方式的GC收集器:Serial, ParNew
  • 空闲列表:
  • 适用场景:堆内存不规整
  • 原理:虚拟机维护内存分配列表,会找到足够大小的内存块分配给实例对象
  • 使用该分配方式的 GC 收集器:CMS

2.内存分配并发问题

  • CAS+失败重试:CAS是乐观锁的一种实现方式,每次不加锁,如果冲突就重试直到成功为止
  • TLAB:为每个线程预先在Eden区分配一块内存,JVM在给线程对象分配内存时,首先在TLAB分配,对象大于TLAB中的剩余内存时候,再采用CAS内存分配

三.初始化零值

虚拟机将分配到的内存空间初始化为零值

保证对象的实例字段在 Java 代码中可以不赋初始值就直接使用

四.设置对象头

虚拟机要对对象进行必要设置,例如这个对象是哪个类的实例,如何才能找到类的元数据信息,对象的哈希码,对象的GC分代年龄等信息,这些信息存在对象头中

五.执行init方法

执行构造方法,赋初值

对象内存布局

对象头

  • 实例数据
  • 对齐填充

对象头:

  1. 存储对象自身的运行数据(哈希码,GC分代年龄,锁状态标志)
  2. 类型指针,对象指向他的类元数据的指针,确定对象是哪个类的实例

六.对象访问的定位

句柄

#JVM学习笔记(二)HotSpot 虚拟机对象创建_java_02

直接指针

#JVM学习笔记(二)HotSpot 虚拟机对象创建_内存分配_03

使用句柄,对象改变,局部变量表的reference不用改变

使用直接指针,对象改变,局部变量表的reference需要改变