写点什么

深入解析 JVM- 类加载机制

作者:janyxe
  • 2022 年 4 月 15 日
  • 本文字数:1596 字

    阅读完需:约 5 分钟

深入解析JVM-类加载机制

前言

本文带着大家初探 JVM 的类加载机制,以及双亲委派机制



一、类加载器加载的过程


类加载过程会经过:


类加载器加载的过程 包括 加载验证准备解析初始化使用卸载

各阶段解析:

  • 加载:在硬盘查找并通过 IO 读取字节码文件,在加载节点生成这个类的 java.class.Class 对象

  • 验证:校验字节码文件的准确性

  • 解析:讲符号引用替换为直接引用

  • 初始化:对类的静态变量初始化为指定的值,执行静态代码块

二、类加载器的分类

  1. 启动类(Bootstrap)加载器:加载 JVM 需要的类,会加 $JAVA_HOME/jre/lib 下的文件 底层是C语言实现

  2. 扩展类(Extension)加载器:由 sun.misc.LauncherExtClassLoader 实现,他会加载 JAVA_HOME/jre/lib/ext 目录中的文件(或由 System.getProperty(“java.ext.dirs”)所指定的文件)。底层是Java实现

  3. 应用类(AppClassLoader)加载器:由 sun.misc.Launcher$AppClassLoader 实现。会加载 classpath 下的 class 及 jar 包。底层是java实现

  4. 自定义加载器

三、双亲委派机制

当我们类加载器收到一个请求的时候,首先会依次向上查找最顶层没有父类的类类加载器 (启动类加载器),依次向下读取 class 文件,如果该类加载器已经读取到 class 文件的时候,子节点不会再继续读取



四、双亲委派源码解析

  1. 首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回

  2. 如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载(即调用 parent.loadClass(name, false);).或者是调用 bootstrap 类加载器来加载

  3. 如果父加载器及 bootstrap 类加载器都没有找到指定的类,那么调用当前类加载器的 findClass 方法来完成类加载


//ClassLoader的loadClass方法,里面实现了双亲委派机制protected Class<?> loadClass(String name, boolean resolve)    throws ClassNotFoundException{    synchronized (getClassLoadingLock(name)) {        // 检查当前类加载器是否已经加载了该类        Class<?> c = findLoadedClass(name);        if (c == null) {            long t0 = System.nanoTime();            try {                if (parent != null) {  //如果当前加载器父加载器不为空则委托父加载器加载该类                    c = parent.loadClass(name, false);                } else {  //如果当前加载器父加载器为空则委托引导类加载器加载该类                    c = findBootstrapClassOrNull(name);                }            } catch (ClassNotFoundException e) {                // ClassNotFoundException thrown if class not found                // from the non-null parent class loader            }
if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); //都会调用URLClassLoader的findClass方法在加载器的类路径里查找并加载该类 c = findClass(name);
// this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { //不会执行 resolveClass(c); } return c; }}
复制代码

五、双亲委派机制好处

为了防御开发者为定义的类与 jdk 定义源码类产生冲突问题,保证该类在内存中的唯一性

六、如何破坏双亲委派

  1. 自定义类加载器 重写 loadClass 方法

  2. Spi 机制绕开 loadClass 方法。当前线程设定关联类加载器



总结

本文主要介绍了类加载器加载的过程以及分类,双亲委派机制原理以及解析等

发布于: 刚刚阅读数: 3
用户头像

janyxe

关注

还未添加个人签名 2020.05.26 加入

还未添加个人简介

评论

发布
暂无评论
深入解析JVM-类加载机制_Java_janyxe_InfoQ写作平台