JVM——类加载机制及双亲委派机制
-
类加载的概念:
- Java运行时编译源码(.java)成字节码(.class),类加载器读取字节码文件,并转换成 java.lang.Class 类的一个实例。
-
类加载器的种类:
- 以下类加载器从上往下是父子类关系。
- 启动类加载器(Bootstrap ClassLoader):加载 JAVA_HOME\lib,或者被 -Xbootclasspath参数限定的类。
- 扩展类加载器(Extension ClassLoader):加载 \lib\ext,或者被 java.ext.dirs 系统变量指定的类。
- 应用程序类加载器(Application ClassLoader):加载 ClassPath 中的类库。
- 自定义类加载器:通过继承 ClassLoader 实现,一般是加载我们的自定义类。
-
双亲委派模型:
- 实现:每次受到类加载请求时,先将请求委派给父类加载器,如果父类加载器无法完成这个加载,子类尝试自己加载。因此所有的加载请求最终都应该传送到顶层的启动类加载器。
- 好处:
- 安全
- 避免同一个类被多次加载
- 每个加载器只能加载自己范围内的类
-
类加载过程:
- 类加载分为三个步骤:加载、连接、初始化
- 类的生命周期: 加载 ——>连接(验证——>准备——>解析)——>初始化——>使用——>卸载
- 加载:
- 根据类的全限定名读取此类的二进制字节流到 JVM 内部;
- 将字节流所代表的静态存储结构转换为方法去的运行时数据结构;
- 转换为一个与目标类型对应的 java.lang.Class 对象;
- 连接:
- 验证:文件格式验证、元数据验证、字节码验证、符号引用验证;
- 准备:为类中的所有静态变量分配内存空间,并为其设置一个初始值;
- 解析:将常量池中所有的符号引用转为直接引用;这个阶段可以在初始化之后再执行。
- 符号引用:和虚拟机实现的内存布局无关,引用的目标不一定已经加载到内存中。
- 直接引用:和虚拟机实现的内存布局相关,引用的目标一定已经加载到内存中。
- 初始化:
- 根据程序员自己写的逻辑去初始化类变量和其他资源。
- 卸载:
- 该类的所有实例都已经被 GC
- 加载该类的 ClassLoader 已经被 GC
- 该类的 java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法
-
热部署:
- 热部署是指在不重启 Java 虚拟机的前提下,能自动侦测到 class 文件的变化,更新运行时 class 的行为。
- 步骤:
- 销毁自定义 classloader
- 更新 class
- 使用新的 ClassLoader 去加载 class
-
何时触发初始化:
- 为一个类型创建一个新的对象实例时(new 、反射、序列化)
- 调用一个类型的静态方法时
- 调用一个类型或接口的静态字段,或者对这些静态字段执行赋值操作时
- 调用 Java API 中的反射方法时
- 初始化一个类的派生类时(会先初始化其父类)
- JVM 启动包含 main 方法的启动类时