当虚拟机遇到一条new指令以后,首先会去检测这个指令的参数能否在常量池中定位到一个类的符号引用,并检测这个类是否被加载、解析、初始化过,没有就先去加载类。
对象创建在堆划分空间可用指针碰撞(使用过的内存放一边未使用的放一边)和空闲列表,划分空间时可能会出现线程不安全的情况#,所以分配内存的时候采用 CAS(Compare and Swap)配上失败重试保证原子性或者采用TLAB(Thread local allocation buffer每个线程在堆中预先分配一块内存),哪个线程需要分配内存,就在该线程的TLAB上分配。
内存分配完后虚拟机需要将内存空间初始化,这样可保证对象被创建以后可以直接使用,比如 new Object() 可直接使用。这里的初始化是指字段置0,并不是赋值
接下来虚拟机会对对象的象头(Object Header)进行设置,比如是哪个类的实例,对象的哈希码,对象的gc分代年龄,如何找到类的元数据信息等。是否启用偏向锁来设置头信息
最后执行init方法,把对象按照程序员的意愿初始化赋值(将对象引用入栈,@暂不确定是init以后入栈还是对象头信息设置完后后入栈)
对象包含三块区域:1、对象头 2、实例数据3、对齐填充
对象头包含两部分信息,一部分是用于存储自身运行时的数据,数据长度可达32或64bit
另外一部分是存储类型指针,即对象指向它的类元数据的指针,虚拟机用它来确定这个对象是哪个类的实例(不是所有虚拟机实现都必须在对象上保留类型指针),如果对象是一个数组,对象头中还必须有一块用于记录数组长度的数据。因为虚拟机可以根据对象所包含的元数据(就是对象包含的所有数据)确定对象需要多大空间,但是无法通过数组的元数据确定数组大小。
实例数据部分是对象真正存储的有效信息,也就是代码中定义的各种类型字段的内容。包括父类继承的和定义的都要记录下来。