一. 对象的创建过程
- 根据new的对象,在常量池中定位所属类的符号引用
- 如果没有找到符号引用,说明这个类没有被加载,就对这个类进行加载
- 加载完成后,jvm为对象分配内存
- jvm将分配的内存空间初始化为0值
当内存分配完成后,虚拟机将分配到的内存都初始化为零值(不包括对象头,引用类型初始值为null,基本类型为零值,布尔类型初始值为false),如果使用TALB这一过程也可以提前至TALB分配时进行,这个过程就可以解释 为什么对象创建后未赋值前就可以直接使用 - 设置这个对象的对象头信息
虚拟机要为对象设置一些必要信息,例如这个对象是那个对象的实例、如何才能找到对象的元数据信息、对象的哈希码、GC的分代年龄等,这些都被设置在对象头(Object Header)中 - 执行构造方法,进行初始化
找出当前对象所属类的继承关系,从继承链中最上层的父类开始,依次执行执行构造方法
虚拟机如何为对象分配内存?
- 第一种虚拟机为对象分配内存叫做
指针碰撞
在这种方式中,认为堆中的内存都是绝对规整的,用过的内存都放在一侧,空闲的空间在另一侧,中间的指针作为指示器,为对象分配空间时,只是将指针向空闲的一侧移动出对象所需内存大小即可,这种方式叫做指针碰撞(Bump the Pointer) - 第二种虚拟机为对象分配内存叫做
空闲列表
如果堆中的内存不是规整的,空闲和被使用的内存交错存在,无法通过简单的指针碰撞方式分配内存,这个时候虚拟机需要维护一张表,用来记录哪些地方的内存可用,在可用内存中,取出对象所需大小,分配给对象,并更些列表
线程安全问题如何解决?
因为堆空间是线程共享的,多线程情况下,如果多个线程申请同一块内存空间,这样就程序异常了,jvm是如何解决的呢?
如果是在TLAB上分配对象的话,那么就不需要担心线程安全问题,如果不是在TLAB上分配内存的话,那么对分配内存的动作进行同步处理,即CAS(compare & swap)搭配失败重试的方式
二. 如何定位到对象
1. 通过直接指针访问对象
对象创建成功后,在栈或者方法区保存一个引用(reference),reference存储是对象地址,直接指向堆中对象的实例数据,同时一个存储一个指向对象类型数据的指针
2. 通过句柄访问对象
reference引用存储是句柄地址,句柄地址存储两个对象和类型数据两个指针,一个指向对象实例数据,一个指向对象类型数据