new 指令
- 先检查常量池中 有没有该类的符号引用,并检查该类是否已被加载 解析和初始化过,如果没有则加载该类
为新生对象分配内存(一个对象所需内存在类加载完成之后便可以确定了)分配内存及把一块确定大小的内存区域从java堆中划分出来
分配方式:
指针碰撞 空闲列表
线程不安全,为保证线程安全:
失败重试 划分缓冲区:即为每个县城划分一个本地线程分配缓冲(TLAB),哪个线程要分配内存就在哪个线程的缓冲区上分配,当TLAB用完时,会为该线程重新分配TLAB
初始化零值
将分配到的内存都初始化为零值,这样对象的实例字段可以不赋初始值就可以使用,程序可以访问到对应数据类型的零值
设置对象头
该对象是哪个类的实例,如何才能找到类的元信息,对象的哈希码(hashcode),对象的GC年龄分代信息,是否使用偏向锁等
init
执行完上述过程程序才被创建,之后会继续执init方法,把对象按照程序员的意愿进行初始化,一个真正可用的对象才被生产出来
对象在内存中的存储
对象在内存中主要有三部分:对象头、 实例数据、 对齐填充
对象头
主要包括运行时数据、 类型指针 运行时数据:hashcode GC分代年龄 锁状态标识 线程持有的锁 偏向线程ID 偏向时间戳 这些称为MarkWord 类型指针:对象指向类元数据的指针,类型指针 数据长度:如果 是java数组 还要有用于记录数组长度的数据(普通对象可以通过类元数据信息获取java对象的大小 而对于数组并不能)
列表内容
子类或者父类中的实例数据都会被记录下来
对齐填充
保证对象的起始地址是8字节的整数被,而用于填充的部分
对象的定位访问
句柄和直接指针
句柄
reference指向java堆中的句柄池,句柄包含了对象实例数据与理性数据的地址
直接指针
接指针存储的就是对象实例数据地址,但实例数据中应该要包含对象类型数据