创建并且new一个类的时候,发生了什么?

Java世界里每天都有大量的类被创建,被使用,被抛弃,那么一个类到底经历了什么?
首先来看看一个类的生命周期,用<<深入理解Java虚拟机>>的图可以清楚的表明,创建并且new一个类的时候,发生了什么?_第1张图片
可以看出来一个类从出生到死亡一共经历了7个步骤,而这里的验证,准备和解析步骤可以统称为连接,所以可以说一个是4个步骤,而这里需要注意的是这5个步骤并不一定是按照顺序执行的。

一.加载

说到加载就不得不说另外一个名词”类加载”, 这两个定义不能混淆,类加载包括”加载”,”验证”,”准备”,”解析”,”初始化”五个步骤,而”加载”是”类加载”全过程的开始。
那么什么时候开始加载?这个并没有强制规定,Java虚拟机只是规定了类进行初始化的时机,而在进行类的初始化时,初始化之前的步骤需要在这之前进行。
那么加载做了什么?其实主要做了三件事

  1. 获取此类的二进制流
  2. 将字节流的静态存储结构转化为方法区的运行时数据结构
  3. 在内存中生成一个java.lang.Class对象
    其实就是从Java虚拟机之外通过二进制流的方式,引入我们需要的类信息,并且存储到虚拟机的方法区,并且生成了一个Class对象作为访问入口。而对于二进制流的引入来源,并没有太多规范。

二.连接

连接包括验证,准备,解析。连接并不是强制性的需要在加载完成之后才进行,在加载时可能连接已经开始。

1.验证

我们知道在Java虚拟机上衍生了许多语言,而这些语言最终都会生成Class文件提供给Java虚拟机进行使用。而验证阶段则是对Class文件中的字节流进行验证,同时也是防止加载阶段输入的字节流对虚拟机造成破坏。所以验证阶段是虚拟机的一种自我保护措施,对于虚拟机十分重要。

所以验证阶段十分严谨,需要完成4个阶段的检查动作:文件格式,元数据,字节码,符号引用验证。而这里的文件格式是在二进制字节流还没有进入到内存区域的检查动作,主要负责检验是否符合Class文件的格式。之后的三种检查动作都是在内存区域进行的,而这里需要提一下的是符号引用检查阶段发生在解析阶段将符号引用转化为直接引用的时候,可以看出来验证贯穿整个连接阶段。

2.准备

准备阶段是为类变量进行分配内存,并且赋予初始量的阶段。有两点需要注意:

  1. 这里是对以static为修饰的类变量进行分配内存
  2. 这里赋予的初始量是指”零值”
    也就是说对于 static int a = 3
    经过准备阶段a在内存中值为0,而不是3

3.解析

解析是指将符号引用转化为直接引用。听起来可能有些抽象,什么是符号引用? 什么又是直接引用?
我们需要知道Class文件结构中常量池的概念,而常量池中存储着两种常量,其中之一就是符号引用,而符号引用包括
1. 类和接口的全限定名
2. 字段的名称和描述符
3. 方法的名称和描述符
通过这些符号来对应引用的目标。

而直接引用则是可以直接指向目标的指针,虽然我们知道Java中并没有指针这一个概念,但是引用指针能够方便理解。

解析主要对类或者接口,字段,类方法,接口方法,方法类型,方法句柄和调用点限定符7类符号引用进行。
下面以CONSTANT_FieldRef_info为例 ,首先对该字段的CONSTANT_Class_info类信息进行解析,然后查找当前的类或者接口有没有符合的字段符号引用,如果匹配返回直接引用,然后在从下往上查找接口中的字段符号引用,再接着查找父类中的字段符号引用。
创建并且new一个类的时候,发生了什么?_第2张图片

三.初始化

初始化阶段执行了类构造器()方法。
对于类中的类变量进行赋值和执行static{} 静态初始块,并且按照顺序执行。而且虚拟机会在调用()方法前调用父类的()方法。如果多个线程对同一个类进行初始化,那么只有一个线程会对这个类进行初始化,其余均会进行堵塞。

四.使用

当完成以上的类加载之后,虚拟机需要对该对象在堆上进行分配内存。而虚拟机分配内存的有两种方法,

  1. 指针碰撞
  2. 空闲列表
    当堆上的内存比较规整的时候,比如当我们采用的是”复制”的垃圾收集算法的时候,会将空闲的内存和已分配的内存各放一边,这种情况下为对象分配内存只需要将指针从已分配内存向空闲内存进行移动,称为指针碰撞
    创建并且new一个类的时候,发生了什么?_第3张图片

否则,则采用的是空闲列表,即虚拟机需要维护一个列表,记录哪些内存是可用的,在分配的时候从列表中寻找一块内存进行分配,并且更新列表。

当对象实例分配内存结束后,虚拟机会为该对象设置信息,如对象是那个类的实例,对象的元数据等,并将这些信息存放在对象头中。

这些步骤进行结束后,对于我们开发人员来说,还是没有结束对象的初始化,Jvm会继续调用对象的方法,为对象的字段赋予初值。

五.卸载

当不再持有该对象的引用的时候,Java虚拟机对当前对象进行垃圾回收操作,回收当前对象的分配的资源。

参考 <<深入理解Java虚拟机>>

你可能感兴趣的:(学习笔记)