JVM学习6·对象以及引用_java

检查加载

首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用(符号引用 :符号引用以一组符号来描述所引用的目标),并且检查类是否已经被加载、
解析和初始化过。

分配内存

接下来虚拟机将为新生对象分配内存。为对象分配空间的任务等同于把一块确定大小的内存从 Java 堆中划分出来。

划分内存的方式有两种:指针碰撞、空闲列表

而划分内存到底使用哪一种方式就要取决于你使用哪一种垃圾回收期,很多都是带有整理功能的,如果是这种的话那就是使用指针碰撞的方式划分内存即可,而如果是GC cms这种垃圾回收期就不带有整理内存的功能,那么就只能使用空闲列表的机制划分内存了。

如果 Java 堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅 是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”。


JVM学习6·对象以及引用_字段_02

如果 Java 堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上 哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”


JVM学习6·对象以及引用_初始化_03

CAS分配机制

有个问题就是效率要差一点


JVM学习6·对象以及引用_初始化_04

分配缓冲机制

有个问题就是受制于Eden区的大小,一般为Eden区的百分之一,如果对象所站用的空间较大就没法使用这个机制来分配空间了,就会使用CAS机制来分配内存空间


JVM学习6·对象以及引用_字段_05

而在JVM是默认开启这种分配机制的:


JVM学习6·对象以及引用_字段_06
JVM学习6·对象以及引用_java_07

内存空间初始化

(注意不是构造方法)内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(如 int 值为 0,boolean 值为 false 等等)。这一步操作保证了对象
的实例字段在 Java 代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。

比如图中代码有两个变量,一个是age,一个是isKing,我们都没有初始化也没有赋值,但是最终还是可以打印出来值,那么内存初始化就是干这个事儿的,把内存中的变量赋初始值。

设置

接下来,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息(Java classes 在 Java hotspot VM 内部表示为类 元数据)、对象的哈希码、对象的 GC 分代年龄等信息。这些信息存放在对象的对象头之中。


JVM学习6·对象以及引用_字段_08

对象初始化

在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象创建才刚刚开始,所有的字段都还为零值。
所以,一般来说,执行 new 指令之后会接着把对象按照程序员的意愿进行初始化(构造方法),这样一个真正可用的对象才算完全产生出来。
构造方法