一般我们new一个新对象的时候,会经过以下5步骤:
- 1.类加载检查
首先会检查这个类是否已经被类加载器加载过了,如果没有被加载过,则会先通过类加载器加载类。 - 2.分配内存
在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类 加载完成后便可完全确定,为对象分配空间的任务等同于把 一块确定大小的内存从Java堆中划分出来。有以下两种分配方式,是会根据GC收集器是采用哪种算法来决定用哪种分配方式。
a.指针碰撞(默认方式)
用过的内存全部放到一边,没用的内存放在另一边,中间有分界值指针,分配地址时只需要将指针向没用的内存移动对象内存大小位置即可(GC收集器:ParNew,Serial)
b.空闲列表
虚拟机维护一个列表,该列表记录那些内存块是可用的,在分配内存时找一块足够大的内存分配给对象实例,然后更新列表记录;(GC收集器:cms)
以下为对象内存分配图
-
3.初始化
内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头), 如果使用TLAB,这一工作过程也 可以提前至TLAB分配时进行。
-
4.设置对象头
在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、 实例数据(Instance Data) 和对齐填充(Padding)。 HotSpot虚拟机的对象头包括两部分信息,第一部分用于存储对象自身的运行时数据, 如哈 希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时 间戳等。对象头的另外一部分 是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
32位的对象头如下所示,64位的类似,只不过有很多未使用的位。
-
5.执行(init)方法
执行(init)方法,即对象按照程序员的意愿进行初始化。对应到语言层面上讲,就是为属性赋值(注意,这与上面的赋零值不同,这是由程序员赋的值),和执行构造方法。