JVM 加载 class 文件的原理机制

JVM 加载 class 文件的原理机制

JVM(Java虚拟机)是一个可以执行Java字节码的虚拟机。它负责执行Java应用程序和应用程序的扩展,如Java库和框架。

文章目录

  • [JVM 加载 class 文件的原理机制](#JVM 加载 class 文件的原理机制)
    • [1. JVM](#1. JVM)
      • [1.1 类加载器](#1.1 类加载器)
      • [1.2 魔数](#1.2 魔数)
      • [1.3 元空间](#1.3 元空间)
    • [2. 类加载](#2. 类加载)

1. JVM

1.1 类加载器

类加载器是JVM用来查找和加载.class文件到JVM中的组件。类加载器的主要职责是从指定的位置找到.class文件,然后将其读入到内存中,并生成对应的java.lang.Class对象。

  • 启动类加载器(Bootstrap ClassLoader) :用原生代码实现,负责加载JVM核心库中的.class文件,如rt.jar中的类。
  • 扩展类加载器(Extension ClassLoader) :由Java实现,负责加载jre/lib/ext目录中的.class文件或由系统变量java.ext.dirs指定的目录中的.class文件。
  • 应用程序类加载器(Application ClassLoader) :由Java实现,负责加载用户类路径(classpath)中的.class文件。
  • 用户自定义类加载器 :可以由用户自己编写,继承自java.lang.ClassLoader,用于特殊目的的类加载。

1.2 魔数

.class文件的开头四个字节被称为魔数(Magic Number)。魔数是0xCAFEBABE,它是用来识别一个文件是否是.class文件。如果文件不是.class文件,或者魔数不匹配,JVM将无法执行该文件。

1.3 元空间

在JVM中,.class文件加载后,类信息被存储在方法区中,这部分内存区域被称为元空间(Metaspace)。元空间是方法区的一部分,用于存储类元数据,包括类的定义信息、静态变量、常量池等。

2. 类加载

2.1 类加载过程

类加载过程大致可以分为以下几个步骤

  1. 加载(Loading) :找到.class文件,并将其读入内存,创建一个java.lang.Class对象。
  2. 链接(Linking) :验证.class文件的正确性,准备类在JVM中运行所需的内存,并解析符号引用。
  3. 初始化(Initialization) :执行类构造器方法<clinit>(),初始化类变量和静态初始化块。

2.2 双亲委派机制

双亲委派模型(Parent Delegation Model)是Java虚拟机(JVM)中类加载机制的核心设计之一。它定义了类加载器之间的加载顺序和委托规则,确保了类加载过程的一致性和安全性。

模型原理

在双亲委派模型中,类加载器分为层次结构,子类加载器会首先请求其父类加载器完成类的加载任务。这个过程遵循:

  1. 当一个类加载器需要加载某个类时,它会首先请求其父类加载器加载该类。
  2. 如果父类加载器能够成功加载该类,则直接返回这个类;如果父类加载器无法加载,则子类加载器会尝试自己加载该类。
  3. 如果子类加载器也无法加载该类,则会抛出ClassNotFoundException异常。

这种委托关系的链条从下往上,一直到达启动类加载器(Bootstrap ClassLoader),它是所有类加载器的顶层,负责加载JVM的核心库(如rt.jar中的类)。

模型优势
  • 避免类的重复加载:由于类加载器之间的委托关系,同一类只会在父类加载器中加载一次,避免了重复加载同一个类,节省了资源。
  • 保证类型安全:所有非启动类加载器都委托给启动类加载器加载核心库中的类,确保了这些类都是由可信的类加载器加载的,从而保证了类型安全。
  • 防止核心API被篡改:核心库的类由启动类加载器加载,任何试图替换这些类的尝试都会被父类加载器拦截,从而保护了Java核心API不被篡改。
模型实现

双亲委派模型的实现依赖于Java的ClassLoader类及其子类。

java 复制代码
public class ClassLoader {
    private ClassLoader parent;

    public ClassLoader(ClassLoader parent) {
        this.parent = parent;
    }

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        // 首先检查是否已经加载过该类
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            try {
                // 如果父类加载器不为空,则委托父类加载器
                if (parent != null) {
                    c = parent.loadClass(name);
                } else {
                    // 如果父类加载器为空,则由Bootstrap ClassLoader加载
                    c = findBootstrapClass(name);
                }
            } catch (ClassNotFoundException e) {
                // 如果父类加载器加载失败,则由当前类加载器加载
                c = findClass(name);
            }
        }
        return c;
    }
    // ... 其他方法 ...
}

ClassLoaderloadClass方法首先尝试从缓存中查找已经加载的类,如果没有找到,则根据双亲委派模型委托给父类加载器加载。如果父类加载器也无法加载,则由当前类加载器负责加载。

相关推荐
王佑辉几秒前
【jvm】HotSpot中方法区的演进
jvm
Domain-zhuo21 分钟前
什么是JavaScript原型链?
开发语言·前端·javascript·jvm·ecmascript·原型模式
Theodore_10221 天前
7 设计模式原则之合成复用原则
java·开发语言·jvm·设计模式·java-ee·合成复用原则
我是苏苏1 天前
Web开发:ORM框架之使用Freesql的DbFrist封装常见功能
java·前端·jvm
天草二十六_简村人1 天前
Java语言编程,通过阿里云mongo数据库监控实现数据库的连接池优化
java·jvm·数据库·mongodb·阿里云·微服务·云计算
老码沉思录1 天前
Android开发实战班 - 数据持久化 - Room 数据库应用
android·jvm·数据库
起名字真南1 天前
【C++】深入理解 C++ 中的继承进阶:多继承、菱形继承及其解决方案
java·jvm·c++·chatgpt·aigc
偶尔。5351 天前
JVM垃圾回收算法详解
jvm
飞滕人生TYF1 天前
在 for 循环中,JVM可能会将 arr.length 提升到循环外部,仅计算一次。可能会将如何解释 详解
java·jvm
customer081 天前
【开源免费】基于SpringBoot+Vue.JS网上订餐系统(JAVA毕业设计)
java·jvm·vue.js·spring boot·spring cloud·java-ee·开源