对象在虚拟机中的创建过程:
1、执行类加载检查
检查new指令的参数能否在常量池中定位到一个类的符号引用,并检查这个符号引用的类是否已被加载、解析和初始化过。如果没有,先执行相应的类加载过程。
2、分配内存
对象所需内存的大小在类加载完成后便完全确定,从java堆中分配一块确定大小的内存出来,有两种分配方式,选择哪种方式由java堆是否规整决定,而java堆是否规整又由垃圾收集器是否带有压缩整理功能决定。
指针碰撞:java堆内存规整,用过的内存和空闲的内存分别放在一边,中间放着一个指针作为分界点,分配内存就是把指针向空闲空间那边移动一段域对象大小相等的距离。
空闲列表:java堆内存不规整,已使用的内存和空闲的内存相互交错,虚拟机维护一个列表记录哪些内存块可用,分配的时候从列表中查找一块足够大的空间划分给对象实例,并更新列表。
线程安全:
可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用原来的指针分配内存的情况,两种解决方案:
a、同步锁定,虚拟机采用CAS配上失败重试的方式保证更新操作的原子性
b、每个线程在java堆中预先分配一小块内存,称为本地线程分配缓冲(TLAB),哪个线程要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才同步锁定。
3、内存空间初始化为零值
不包括对象头,保证了对象的实例在java代码中可以不赋初始值就直接使用,程序能访问到各个字段的数据类型所对应的零值。
4、设置对象头
从虚拟机视角来看,一个新的对象已经产生了,但从java程序视角来看,所有字段都还是零值,还要执行代码中的初始化,一个真正可用的对象才算完成。