JVM 类加载器工作流程

类加载器

  classloader:谈到类加载,不得不提的就是负责此项工作的类加载器 classloader,classloader 的职责是将 Java 源文件编译后的字节码文件加载到内存中去执行。

  类加载至卸载过程

  

  步骤一、类加载机制

当系统运行时,类加载器将.class 文件的二进制数据从外部存储器(如光盘,硬盘)调入内存中,CPU 再从内存中读取指令和数据进行运算,并将运算结果存入内存中。内存在该过程中充当着“二传手”的作用,通俗的讲,如果没有内存,类加载器从外部存储设备调入.class 文件二进制数据直接给 CPU 处理,而由于 CPU 的处理速度远远大于调入数据的速度,容易造成数据的脱节,所以需要内存起缓冲作用。

  类将.class 文件加载至运行时的方法区后,会在堆中创建一个 Java.lang.Class 对象,用来封装类位于方法区内的数据结构,该 Class 对象是在加载类的过程中创建的,每个类都对应有一个 Class 类型的对象,Class 类的构造方法是私有的,只有 JVM 能够创建。因此 Class 对象是反射的入口,使用该对象就可以获得目标类所关联的.class 文件中具体的数据结构。

  类加载的最终产物就是位于堆中的 Class 对象(注意不是目标类对象),该对象封装了类在方法区中的数据结构,并且向用户提供了访问方法区数据结构的接口,即 Java 反射的接口。

  步骤二、连接过程

(1)验证:确保被加载类的正确性,即确保被加载的类符合 javac 编译的规范

  (2)准备:为类的静态变量分配内存,并初始化为默认值

  (3)解析:将类中的符号引用转化为直接引用

   注:符号引用即一个 Java 源文件在被编译时,在不清楚被引用类实际内存地址的情况下,会使用能唯一识别并定位到目标的符号来代替。如 A 类引用了 B 类,编译时 A 并不知道 B 类实际的内存地址,故可以使用能唯一识别 B 的符号来代替。而当类加载时,编译后的.class 文件实际已被调入内存,可知道 A,B 类的实际内存地址,当引用的目标已被加载入内存,则此时的引用为直接引用。

  步骤三、初始化

初始化过程为类的静态变量赋予正确的初始值(与连接过程的准备阶段不同,如 int 类型的静态变量,JVM 的默认值为 0,遇到 static int a = 3 的代码时,准备阶段首先是赋值为 0,初始化阶段才赋值为 3)