Java 虚拟机(JVM) 的类加载过程

类的生命周期

一个类从加载到虚拟机内存中到卸载出内存要经历七个阶段,依次为加载、验证、准备、解析、初始化、使用和卸载,其中验证、准备和解析统称为连接。

Java 虚拟机(JVM) 的类加载过程

加载、验证、准备和初始化是严格的按照顺序开始(不是进行或完成)的,解析阶段在某些阶段是在初始化之后开始的。这样做是为了支持 Java 语言的运行时绑定特性。

类的加载过程

加载

加载阶段虚拟机需要完成三件事情,

  1. 通过一个类的全限定名获取定义此类的二进制字节流。
  2. 将二进制字节流所代表的的静态存储结构转换为方法区的运行时数据结构。
  3. 在虚拟机内存中创建一个代表这个类的 java.lang.Class 对象,作为方法区这个类的数据的访问入口。

验证

这一阶段的的目的是确保 Class 文件的字节流中包含的信息符合《Java 虚拟机规范》的全部要求,确保这些信息被当做代码运行后不会危害到虚拟机的安全。

验证阶段大致上要完成四个检验动作:文件格式验证、元数据验证、字节码验证和符号引用验证。

文件格式验证

此阶段要验证字节流是否符合 Class 文件格式的规范,以及是否能被当前虚拟机正确处理。

这阶段的验证是基于二进制字节流进行的,只有通过了这个阶段的验证后,字节流才会被允许进入 Java 虚拟机内存的方法区中进行存储。后面的三个阶段的验证都是基于方法区中的存储结构进行的,不会直接读取和操作字节流了。

元数据验证

第二阶段是对字节码描述的信息进行语义分析,确保它符合《Java 虚拟机规范》的要求。

字节码验证

这个阶段的主要目的是通过数据流分析和控制流分析,确定程序语义是合法的、符合逻辑的。

这个阶段是对类的方法体进行校验分析,确保被校验的类的方法在运行时不会做出危害虚拟机安全的行为。

符号引用验证

最后一个阶段的校验行为反正在虚拟界将符号引用转换为直接引用的时候,即连接的第三个阶段 ——解析阶段进行。

这个阶段的目的就是确保解析行为能正常执行。

准备

准备阶段是为类中定义的类变量即静态变量分配内存,并设置初始值的阶段。初始值通常情况下是数据类型的零值。如果一个类变量被定义为了常量(被 final 修饰),那么在准备阶段变量就会被初始化为指定的初始值。

解析

解析阶段是 Java 虚拟机将常量池中的符号引用转换为直接引用的过程。

初始化

直到初始化阶段,Java 虚拟机才真正开始执行类中编写的程序代码。在初始化阶段,会根据程序员的编码的意愿去初始化类变量和其他资源。也就是说,此时是执行类构造器 <clinit>() 方法的阶段。