曹耘豪的博客

JVM之类加载

  1. 类加载时机
  2. 类加载过程
    1. 加载阶段
    2. 验证阶段
    3. 准备阶段
    4. 解析阶段
    5. 初始化阶段
  3. 类的唯一性
  4. 类加载器
  5. JVM类加载机制
  6. 双亲委派模型
    1. 工作流程
    2. 双亲委派机制
  7. 自定义类加载器

Update on 2023/02/27

类加载时机

分为隐式加载显示加载

隐式加载:

显示加载:

类加载过程

包括加载验证准备解析初始化五个阶段。

在这五个阶段中,加载验证准备初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。

加载阶段

验证阶段

准备阶段

为类的静态变量在方法区分配内存,并将其初始化为默认值

注意:

解析阶段

将常量池内的符号引用替换为直接引用

初始化阶段

为静态变量赋予正确的初始值

类的唯一性

一个类的唯一性由以下2点决定:

类加载器

示例:

1
2
3
4
ClassLoader loader = Thread.currentThread().getContextClassLoader();
System.out.println(loader);
System.out.println(loader.getParent());
System.out.println(loader.getParent().getParent());

结果:(BootstrapLoader(引导类加载器)是用C语言实现的,所以返回为null

1
2
3
sun.misc.Launche r$AppClassLoader@64fef26a
sun.misc.Launcher$ExtClassLoader@1ddd40f3
null

JVM类加载机制

双亲委派模型

工作流程

如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,

双亲委派机制

  1. AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。
  2. ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。
  3. 如果BootStrapClassLoader加载失败(例如在 $JAVA_HOME/jre/lib里未查找到该class),会使用 ExtClassLoader来尝试加载;
  4. ExtClassLoader也加载失败,则会使用 AppClassLoader来加载,如果 AppClassLoader也加载失败,则会报出异常 ClassNotFoundException

自定义类加载器

  1. 继承ClassLoader
  2. 实现findClass方法,其中调用defineClass将字节码转为Class对象
1
2
3
4
5
6
7
8
9
10
11
public class MyClassLoader extends ClassLoader {

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {

byte[] bytes; // Loaded class binary;

return defineClass(name, bytes, 0, bytes.length);
}

}
   / 
  ,