Java对象实在堆中创建,主要分为以下五步:
一. 类加载
检查常量池中是否能定位到类的符号引用,并检查当前类是否被加载解析和初始化过;如果没有则必须执行类加载。
二.分配内存
虚拟机为对象分配内存,分配内存的方式主要有两种:
1.指针碰撞
将指针向空闲内存方向移动对象大小的距离。这种方式需要Java堆中内存是绝对规整的。
2.空闲列表
如果堆中的内存并不规整,如已使用的堆内存与空闲的堆内存相互交织在一起,则不能使用指针碰撞进行内存分配;这个时候虚拟机需要维护一个列表记录堆中的空闲内存的大小,在内存分配的时候通过查询空闲列表找到一块足够大的内存分配空间。
Java堆内存是否规整是由垃圾收集器是否带有空间压缩整理来决定的;如Serial、ParNew带压缩整理过程的收集器采用的是指针碰撞来进行空间分配;CMS是基于清除算法的,采用的是通过空闲列表拿到一块较大的缓冲区之后,在缓冲区里面仍然使用指针碰撞来分配空间。
注意:为防止并发分配内存时出现的问题,Java虚拟机采用以下两种方式来解决:
1、采用CAS配上失败重试机制保证更新的原子操作;
2、每个线程在Java堆中预先分配一小块内存,称为本地线程缓冲区(Thread Local Allocation Buffer,TLAB),那个线程需要分配内存就在缓冲区中分配,只有本地缓冲区用完了,分配新的缓冲区的时候才需要同步锁定。虚拟机是否使用TLAB可通过-XX:+/-UseTLAB参数来决定;本地线程缓冲区是线程私有的
三. 初始化
内存分配完成后,虚拟机必须将分配到的内存空间(不包括对象头)都初始化为零值;采用TLAB分配内存的的话,初始化可在TLAB分配时顺便进行。
四.设置对象信息
设置元数据信息,对象GC分代年龄,锁信息等。
五.实例化
调用构造函数即Class文件中的init()方法,之后对象才算完全的构造出来。