类加载系统

目录

类加载过程

加载

链接

初始化

类加载器

BootstrapClassLoader

ExtClassLoader

AppClassLoader

类加载器间的关系

双亲委派机制

概述

优点

类加载过程

加载

通过完全限定名获取字节码数据流,将其加载进内存

链接

  • 验证:字节码格式等数据是否正确
  • 准备:静态变量分配内存,并赋值为对应数据类型的默认值
  • 解析:类中指向常量池的符号引用转为直接引用

初始化

静态变量显示赋值,执行静态代码块

类加载器

BootstrapClassLoader

C 语言实现,JVM 启动时创建该类加载器,属于 JVM 的一部分,加载 <JAVA_HOME>/lib 下的核心类

ExtClassLoader

是 sun.misc.Launcher 类中的一个静态内部类,加载 <JAVA_HOME>/lib/ext 下的类

java 复制代码
package sun.misc;

public class Launcher {

    // 扩展类加载器
    static class ExtClassLoader extends URLClassLoader {
        
    }
}

AppClassLoader

是 sun.misc.Launcher 类中的一个静态内部类,加载 classpath 类路径下的类

java 复制代码
package sun.misc;

public class Launcher {

    // 应用程序类加载器
    static class AppClassLoader extends URLClassLoader {
        
    }
}

类加载器间的关系

体现在 sun.misc.Launcher 类的构造方法,BootstrapClassLoader 作为 ExtClassLoader 的父加载器,ExtClassLoader 作为 AppClassLoader 的父加载器

java 复制代码
package sun.misc;

public class Launcher {
    
    public Launcher() {
        ExtClassLoader var1;
        try {
            // 创建ExtClassLoader,将其parent属性设置为null(BootstrapClassLoader并非Java语言编写)
            var1 = Launcher.ExtClassLoader.getExtClassLoader();
        } catch (IOException var10) {
            throw new InternalError("Could not create extension class loader", var10);
        }

        try {
            // 创建AppClassLoader,并将它的parent属性设置为ExtClassLoader
            this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
        } catch (IOException var9) {
            throw new InternalError("Could not create application class loader", var9);
        }

        // 设置AppClassLoader为线程上下文类加载器
        Thread.currentThread().setContextClassLoader(this.loader);

    }
    
}

双亲委派机制

体现在 java.lang.ClassLoader 类中的 loadClass 方法

概述

当某个类加载器加载某个类时,首先调用 native 本地方法 findLoadedClass0 方法检查该类是否已经被加载,已经被加载就直接返回,若没有被加载,则调用 parent 父类加载器的 loadClass 方法将类加载任务交给父类加载器,当到 ExtClassLoader,将类加载任务给 BootstrapClassLoader,不在父类加载器的加载范围加载不了,则类加载任务再由子类加载器加载

java 复制代码
package java.lang;

public abstract class ClassLoader {

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            // 先检查该类是否已经被加载过
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // 该类未被加载
                    if (parent != null) {
                        // 如果其parent父类加载器不为空,则调用父类加载器的loadClass方法
                        c = parent.loadClass(name, false);
                    } else {
                        // parent父加载器为null,则当前类加载器为ExtClassLoader,则交给BootstrapClassLoader
                        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();
                    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;
        }
    }

}

优点

  • 防止同一个类被不同的类加载器重复加载
  • 提高安全性,防止 Java 核心类被篡改
相关推荐
java_upp6 小时前
JVM内存溢出和内存泄漏的区别及排查方法
jvm·内存泄漏·内存溢出
城管不管17 小时前
MySQL 慢查询完整排查
java·服务器·jvm·数据库·mysql·spring·面试
mister_guo1 天前
JVM 内存管理原理及生产配置实战:从“参数能启动”到“内存可控”
java·jvm
名字还没想好☜2 天前
Go 的 strings.Builder 实战:拼接性能、Grow 预分配与何时该用 bytes.Buffer
java·jvm·后端·golang·go
wear工程师3 天前
Java 类初始化到底何时触发?别把加载、连接和 static 执行混在一起
java·jvm
程序员雷欧3 天前
线上频繁触发各种 GC 的原因排查与处理指南
java·jvm·算法
wuminyu3 天前
JVM利用io_uring优化堆外内存性能原理剖析
java·linux·c语言·jvm·c++
147API5 天前
Python批量生成蒸馏数据,并发、重试、幂等和断点续跑
开发语言·jvm·python
wuminyu5 天前
JDK21解决虚拟线程IO阻塞原理剖析
java·linux·c语言·jvm·c++
sunywz5 天前
【JVM】(8)JVM调优实战及常量池详解
jvm