java的类加载浅析
类加载
类加载器
类加载器是Java虚拟机(JVM)的一个组成部分,它的主要任务是在运行时动态加载类和资源,以便程序能够使用它们。类加载器从文件系统、网络或其他来源中获取类的字节码,并将其转换为JVM可执行的形式,这样程序就可以使用这些类和资源了。
类加载器分类
java9之前
当JVM启动时,会形成有3个类加载器组成的初始类加载器层次结构:
- Bootstrap ClassLoader:根类(或叫启动、引导类加载器)加载器。加载核心库,如
rt.jar
。- Extension ClassLoader:扩展类加载器。主要加载
lib/ext
下面的 jar 包- System ClassLoader(或Application ClassLoader):系统类加载器。负责加载
classpath
下的类
java9的变化
尽管JDK 9保持了三级分层类加载器架构以实现向后兼容,但是模块系统加载类的方式已经发生了一些变化。此外,Platform ClassLoader(平台类加载器)取代了Extension ClassLoader(扩展类加载器),平台类加载器其作用在于加载一些平台相关的模块,例如:java.activation、java.se、jdk.desktop、java.compiler等。JDK9类加载器层次结构如下图所示。
类生命周期
类的生命周期由7个阶段组成,类加载说的是前5个阶段:即加载—>验证—>准备—>解析—>初始化
(其中验证->准备->解析三个可以合为连接过程)
各个阶段的解释
加载:通过类装载器将编译后的.class文件加载到内存中,并在
堆区
创建出一个Class对象,用来描述这个类的类型信息。系统中所有的类都是java.lang.Class的实例。在这个阶段,还会进行验证.class文件的格式等操作。连接:在这个阶段,Java虚拟机会对类进行验证、准备和解析。
- 验证:验证阶段是对类的结构和语义进行检查,确保它符合Java语言规范。这包括检查类的继承关系、方法重载、访问控制等。验证阶段是为了确保类在运行时不会出现异常或安全问题。
- 准备:在此阶段,Java虚拟机会为类的静态变量(static变量)分配内存,并设置默认值。例如,静态整数变量默认值为0,静态布尔变量默认值为false等。需要注意的是,在这个阶段并不会执行静态变量的初始化代码。
- 解析(可选的):将常量池内的符号引用替换为直接引用。符号引用是类中对其他类、字段或方法的引用,它包括类名、字段名和方法名等信息。直接引用则是指向内存中实际对象或方法的指针。解析阶段保证了类在运行时可以找到它所依赖的其他类、字段和方法。
比如,现在有个方法play(),这个方法的地址是666666,那么play就是符号引用,666666就是直接引用。
初始化:此阶段Java虚拟机会执行类的静态初始化代码,包括静态变量的赋值和静态块的执行。类构造器方法
<clinit>
会被执行,由JVM负责保证线程安全和只执行一次。在这个阶段,会按照静态变量定义的顺序依次执行相应的赋值操作。
对象构造器方法
<init>
:new一个对象的时候被调用类构造器方法
<clinit>
:类加载的初始化阶段jvm会调用<clinit>
方法
- 使用:初始化阶段完成后,类进入使用阶段。在这个阶段,程序可以创建类的实例、调用类的方法、访问类的字段等。使用阶段是类的主要活动期,它可能持续很长时间。
- 卸载:类的生命周期最后进入卸载阶段。在这个阶段,Java虚拟机会回收类占用的内存资源,释放与类相关的所有资源。只有在其定义的类加载器可以被垃圾回收器回收的情况下,类或接口才能被卸载。
补充:卸载需要满足:
- 该类所有的实例已经被回收
- 加载该类的类加载器被回收
- 该类对应的java.lang.Class对象没有任何对方被引用
三种类加载器加载的类在虚拟机的整个生命周期中是不会被卸载的,只有用户自定义的类加载器所加载的类才可以被卸载