对象的创建过程
遇到一条new指令时,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,通过这个引用检查类是否已被加载,解析和初始化过,如果没有就先执行类加载
-
类加载完成后,虚拟机为新生成的对象分配内存(这个过程是把一块确定大小的内存从java堆中分配出来)。
- 如果java堆中的内存很规整即一边是已用内存另一边是空闲内存,中建房一个指针作为分界点的指示器,那么这个分配过程就是将该指针移向空闲区域与该对象大小相等的距离。这种分配方式配称为指针碰撞。
- 如果堆中的内存不是规整的,而是相互交错的,虚拟机就必须维护一个表,记录哪些内存块是可用的,分配的时候就在列表上找到一块足够大的空间划分给这个实例,然后更新这个表。这种分配方式叫做空闲列表。
- java堆是否规整由所采用的垃圾收集器是否带有压缩整理功能。
对象创建在虚拟机中很频繁,仅仅修改一个指针指向的位置,在并发情况下并不是线程安全的,解决方法有二
- 分配内存空间的动作进行同步处理,采用CAS和失败重试保证了更新操作的原子性
- 把内存分配的动作按照线程划分在不同的空间中进行,即每个线程在java堆中预先分配一块内存,这个内存被称为本地线程分配缓冲TLAB,哪个线程要分配内存,就在那个线程得TLAB上分配,只有在TLAB用完并分配新的TLAB时,才需要同步锁定。
内存分配完成后,虚拟机就要将这块内存空间都初始化为0值(对象头除外),如果使用TLAB这个工作将提前到TLAB分配的时候进行,这个操作就保证了对象的实例字段在Java代码中可以不赋初始值就可以使用。
之后虚拟机将对对象进行必要的设置,比如对象是哪个类的实例,如何才能找到类的元数据信息,对象的哈希码,对象的GC分代年龄等信息。这些信息在对象的对象头中。
前面4步完成后从虚拟机的角度上来看,对象已经创建完成,但是对于jaba程序<init>方法还没有执行,所有的字段都是0。所以之后会执行<init>方法,将对象按照程序员的意愿初始化。
这样一个真正可用的对象就完全产生出来了。