重学JVM之类加载机制

本文详细解析了Java类加载过程,包括加载、验证、准备、解析和初始化阶段。重点介绍了类加载器的工作原理,以及双亲委派模式如何确保系统的安全性。

java文件编译成class文件之后,必须要放到java虚拟机才能执行,类的整个生命周期如下
在这里插入图片描述
第一步我们是进行加载,加载是由类加载器进行加载的,也就是说把clss文件变成字节流,然后放到虚拟机的一个过程,其中方法区放的是类信息,静态变量,常量,编译后的代码,同时在堆中生成一个代表该类的对象,作为方法区访问的入口

类加载器工作原理如下

    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) {
                        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();
                    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;
        }
    }

1、首先检查这个类是否已经被加载,如果被加载过,返回该类的对象
2、如果没有被加载过,并且如果父加载器不为空,那么调用父加载器的loadClass方法加载类,如果父加载器为空,那么调用虚拟机的加载器(bootstrap classLoader)来加载类。
3、如果还没有成功的加载到类,那么就调用自己的findClass(name)来加载类

其实就是通过递归调用查找顶层父类去加载,如果都加载不了,才会交给自定义的类去加载,这就是双亲委派模式,也就是说有加载类请求的时候优先从父类加载,父类搜索不到该类的路径时,才会交由自定义的类加载器完成加载请求,这样做的目的是为了安全考虑,比如说用户自定义一个java.util.hashmap,但是由于这个类已经由启动类加载器加载了,这个时候自定义的这个路径是不会再重新加载一次了

在这里插入图片描述

验证阶段主要就是验证魔数,版本号,文件格式等
准备就是为类变量分配内存并设置初始值,解析就是将符号引用替换为直接引用的过程。

### JVM加载机制原理 JVM 的类加载机制是一种动态加载的方式,它允许 Java 应用程序在运行时按需加载所需的类文件。这种机制的核心部分由 **双亲委派模型** 和 **类加载器层次结构** 组成。 #### 双亲委派模型的工作方式 当一个类加载器收到类加载请求时,它不会立即尝试自己去加载该类,而是先把这个请求委托给它的父类加载器处理。这一过程会逐级向上直到到达顶层的启动类加载器(Bootstrap ClassLoader),只有当父类加载器无法完成加载任务时,当前类加载器才会尝试自行加载目标类[^1]。 #### 类加载器的层次结构 JVM 中存在三种主要类型的类加载器以及一种可选的自定义类加载器: - **启动类加载器 (Bootstrap ClassLoader)** 负责加载位于 `JAVA_HOME/jre/lib` 下的核心类库,例如 `java.lang.*` 系列包中的类[^4]。 - **扩展类加载器 (Extension ClassLoader)** 加载存放在 `JAVA_HOME/jre/lib/ext` 或者通过 `-D java.ext.dirs` 参数指定位置上的 JAR 文件中的类。 - **应用程序类加载器 (Application ClassLoader)** 这是最常见的类加载器之一,默认用于加载用户的应用程序代码所在的路径下(即 CLASSPATH 所指明的位置)的所有类。 - **自定义类加载器** 开发人员可以通过继承 `ClassLoader` 来创建自己的类加载器以满足特定需求。如果不希望破坏现有的双亲委派模式,则只需覆盖其子方法 `findClass()` 即可;而要改变默认行为并绕过此规则,则需要重新编写 `loadClass()` 方法来实现新的逻辑[^3]。 #### 类加载的过程阶段划分 整个类加载可以分为以下几个重要阶段: 1. **加载**: 将字节码读入内存,并将其转换为对应的二进制数据流形式存储于方法区中; 2. **验证**: 对输入的数据进行校验,确保它们符合虚拟机规范的要求,防止潜在的安全隐患; 3. **准备**: 创建静态变量并将这些字段初始化为其所属类型规定的初始值; 4. **解析**: 把常量池内的符号引用替换成为直接引用; 5. **初始化**: 设置类的静态变量到正确的初始值,并执行任何必要的静态语句块操作。 以上就是关于 JVM 如何利用双亲委派模型及其背后的分类体系来进行有效的类管理的一个概述说明。 ```python class CustomClassLoader(ClassLoader): def findClass(self, name): # 自定义查找逻辑 byte_array = self.loadByteCode(name) return super().defineClass(byte_array) def loadByteCode(self, className): with open(f"{className}.class", 'rb') as f: return bytearray(f.read()) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值