java对象的创建

在语言层面,创建一个对象仅仅是new一个关键字,但是在虚拟机中,对象的创建过程应该是怎么样的?

检查类是否加载

虚拟机遇到一条new指令的时候,首先会检查该指令的参数能否在常量池定位到一个类符号引用,检查该类符号引用代表的类是否被加载、解析和初始化过,如果没有,就先执行类加载过程。

划分内存空间

在通过类加载过程之后,接下来虚拟机为新生对象分配内存,为对象分配空间等同于把一块确定大小的内存从java堆中划分出来。

有两种分配方式:指针碰撞和空闲列表。

指针碰撞,如果内存是绝对规整的,一边是用过的内存,一边是空闲的内存,那么可以用一个指针表示其中间的分界线,那么分配内存的方式就是把指针向空闲内存的一边移动与对象大小相等的距离。

空闲列表,如果内存不是规整的,用过的内存和空闲的内存相互交错,虚拟机维护了一个列表,列表上记录了内存中哪些区域是可用的,分配内存的方式就是在列表中找到一块内存足够大的空间分配给对象,并更新列表上的记录。

分配空间的安全性

还需要考虑的是,创建对象在虚拟机中是否频繁。仅仅是改变一个指针指向的位置,在并发情况下,也不是安全的,可能会出现还没来得及给对象A分配内存,对象B同时使用了原来的指针来分配内存。解决这类问题有两种方式:

1.对分配空间的动作进行同步处理,虚拟机采用CAS操作和失败重试的方式保证了更新操作的原子性。

2.内存分配的动作按照线程的划分在不同的空间上进行。即每个线程预先在Java堆中预先申请一小块内存区域,称为本地线程分配缓存(TLAB)。哪个线程需要分配内存,就在哪个线程的TLAB上分配缓存。

内存空间的初始化

内存分配完之后,虚拟机将分配到内存空间初始化为0值。如果虚拟机采用了TLAB,这一步可以提前到TLAB分配时进行。这一步保证了,对象的实例字段在java代码中可以不赋初始值就可以使用。

对象设置头信息

接下来,虚拟机要对对象进行必要的设置,比如,该对象是哪个类的实例,如何找到该类的元数据信息,对象的哈希码,对象的GC分代年龄等信息。这些设置放在对象头里(Object Header)。

<init>方法初始化

从虚拟机的角度来看,对象已经创建好了,从java程序来看,这才刚刚开始,<init>方法还没执行,程序所有字段都为零,一般来说,执行完new指令后就会紧接着执行<init>方法,把对象按照程序员的意愿进行初始化。

这样,一个真正可用的对象才算创建出来。

Last modification:November 6th, 2019 at 02:46 pm
如果觉得我的文章对你有用,请随意赞赏