JVM类加载器大比拼:谁才是Java程序的真正主宰?

类加载器

  • 概述
  • 类加载器定义
  • 类加载器种类
    • 启动类加载器
    • 扩展类加载器
    • 系统类加载器
    • 自定义类加载器
    • 继承关系
    • 特点
  • 类加载机制
  • 类名称空间
  • 性能优化

主页传送门:📀 传送

概述

  JVM(Java虚拟机)的类加载器是Java的核心组件之一,负责将Java字节码文件加载到JVM中,并将其转换为可以执行的Java类。

类加载器的主要职责:

  1. 加载类:根据类的全限定名,将类的字节码文件加载到JVM中,并为其创建一个Class对象。
  2. 链接类:验证类的字节码是否符合Java虚拟机规范,并准备类的静态变量(即初始化静态变量为默认值)。
  3. 初始化类:执行类的静态初始化代码,包括静态变量初始化和静态代码块执行。

类加载器定义

  类加载器是Java虚拟机(JVM)中的一个组件,它的主要作用是将Java源代码编译成可执行的字节码,并将其加载到JVM中。

  类加载器在Java中扮演着关键的角色,它们使Java具备了动态加载和隔离不同类的能力。具体来说,类加载器负责从文件系统、网络或其他来源读取类文件(.class文件),并将其转换为JVM中的可执行代码。这个过程分为两个步骤:首先是加载类,通过读取类文件并创建一个代表该类的Class对象;其次是链接类,包括验证、准备和解析类文件中的符号引用。

  类加载器还遵循双亲委派模型,即子类加载器在收到类加载请求时,首先将请求委派给父类加载器,只有在父类加载器无法完成加载请求时,子类加载器才会尝试自己去加载。这种机制可以保证Java核心API的稳定性和防止某些安全问题。

类加载器种类

  类加载器主要有三种:启动类加载器、扩展类加载器和系统类加载器。启动类加载器负责加载Java核心类库,扩展类加载器负责加载java.ext.dirs系统属性中指定的目录或JDK安装目录的lib/ext子目录下的类库,而系统类加载器则负责从Classpath环境变量中加载应用相关的类。

启动类加载器

  Bootstrap ClassLoader(启动类加载器)是Java虚拟机(JVM)中的一种特殊类加载器,它是JVM的内部组成部分,主要负责加载Java核心类库,如java.lang包中的类以及其他基础的类,这些类通常是JVM运行所必需的类。

Bootstrap ClassLoader主要特点

  1. 加载核心类库: Bootstrap ClassLoader负责加载JVM运行时环境所需的核心类库,这些类库通常包括Java标准库中的一些基础类,如Object类、String类等。这些类在JVM启动时就会被加载,因此无法通过普通的类加载器重新加载或替换。

  2. 不是普通的ClassLoader: Bootstrap ClassLoader 不是普通的Java类加载器,它通常是用本地代码(C/C++)实现的,与普通的Java类加载器不同。这使得它能够加载基础类库,而不受Java应用程序的类加载器体系的影响。

  3. 无法被替换: 由于Bootstrap ClassLoader加载的类是JVM运行所必需的核心类库,它们不能被普通的Java类加载器替换或重新加载。这确保了JVM的稳定性和安全性。

  Bootstrap ClassLoader是JVM的内部组件,负责加载JVM运行所需的核心类库,具有特殊的地位和特点,通常不会被普通的Java应用程序代码所涉及。

示例:

public class Main {
    public static void main(String[] args) {
        // 使用核心类
        String message = "Hello, World!";
        System.out.println(message);
        
        // 使用Object类
        Object obj = new Object();
        
        // 等等...
    }
}

扩展类加载器

  Extension ClassLoader(扩展类加载器)是Java虚拟机(JVM)的一个重要组成部分,它的主要职责是加载Java标准扩展库中的类和用户自定义的扩展类。
Extension ClassLoader主要职责工作方式

  1. 加载扩展类库: Extension ClassLoader负责加载位于JRE(Java Runtime Environment)的lib/ext目录下的JAR文件中的类。这些JAR文件包含了Java标准扩展库,例如Java Cryptography Extension(JCE)或Java Naming and Directory Interface(JNDI)等。

  2. 工作方式: Extension ClassLoader是JVM中的一个普通的Java类加载器,它的工作方式与其他普通的类加载器类似,但有一点不同,它是通过父类加载器的方式工作的。通常情况下,Extension ClassLoader的父类加载器是Bootstrap ClassLoader。这意味着它首先会尝试从Bootstrap ClassLoader加载类,如果找不到类,它才会尝试从自己的类路径中加载。

  3. 类路径: Extension ClassLoader的类路径通常包括JRE的lib/ext目录下的JAR文件。这个类路径是通过系统属性 java.ext.dirs 来指定的。

  4. 用户自定义扩展类: 除了加载标准扩展库,Extension ClassLoader还可以加载用户自定义的扩展类,只要这些类位于java.ext.dirs目录下或其子目录中。这允许开发人员将自己的扩展类添加到JRE,以扩展Java的功能。

  Extension ClassLoader的主要职责是加载Java标准扩展库中的类和用户自定义的扩展类,它通过委派给Bootstrap ClassLoader来加载标准扩展库中的类,同时也可以加载用户自定义的扩展类。这有助于扩展Java的功能和功能。

示例:

public class Main {
    public static void main(String[] args) {
        // 使用Extension ClassLoader加载自定义扩展类
        MyExtensionClass extensionClass = new MyExtensionClass();
        extensionClass.printMessage();
    }
}

系统类加载器

  Application ClassLoader(应用程序类加载器),也被称为System ClassLoader,是Java虚拟机(JVM)中的一种类加载器。它的主要作用是加载应用程序开发者编写的Java类,这些类通常位于应用程序的类路径(Classpath)下。
Application ClassLoader在应用程序中的作用

  1. 加载应用程序类: Application ClassLoader负责加载应用程序开发者编写的Java类,包括应用程序的主类和所有相关的库和依赖。这些类通常位于应用程序的类路径中,可以通过CLASSPATH环境变量或者 -classpath 命令行参数来指定。

  2. 应用程序隔离性: Application ClassLoader为不同的Java应用程序提供了隔离性。不同的Java应用程序可以拥有自己独立的类加载器实例,这样它们不会相互干扰,即使它们使用相同的类名也不会发生冲突。这有助于确保应用程序的独立性和隔离性。

  3. 动态加载: Application ClassLoader允许应用程序在运行时动态加载类。这对于插件化架构和动态模块加载非常有用,应用程序可以根据需要加载额外的类,而无需重新启动。

  4. 类版本控制: Application ClassLoader还负责管理和控制已加载类的版本。如果应用程序需要升级某个类,它可以确保加载新版本的类而不会与旧版本发生冲突。

  Application ClassLoader在应用程序中的主要作用是加载应用程序开发者编写的Java类,提供应用程序隔离性,支持动态加载,并管理类的版本控制。这是Java应用程序在JVM中正常运行的关键组成部分。

示例:

public class Main {
    public static void main(String[] args) {
        /* 
        使用Application ClassLoader加载类
        Application ClassLoader会自动加载应用程序类 
        */
        MyClass myObject = new MyClass();
        myObject.printMessage();
    }
}

class MyClass {
    public void printMessage() {
        System.out.println("Hello from MyClass!");
    }
}

自定义类加载器

  除了上述三种类加载器,还有一种比较特殊的类加载器——自定义类加载器(Custom Class Loader)。自定义类加载器允许开发者自己实现类加载器的逻辑,以满足特定场景的需求。这些类加载器需要继承自ClassLoader类,并重写findClass()方法来指定加载过程。例如,可以实现一个加载指定路径下所有jar文件的类加载器,或者实现一个加密/解密字节码的类加载器等。想了解更多自定义类加载器的可以看上文动态类加载

继承关系

  在Java中,类加载器的继承关系为:ClassLoader ->SecureClassLoader -> URLClassLoader -> AppClassLoader -> ExtClassLoader -> BootstrapClassLoader。其中,AppClassLoaderExtClassLoader是系统类加载器和扩展类加载器的实例,而BootstrapClassLoader是启动类加载器的实例。开发者可以通过继承ClassLoader类或URLClassLoader类来实现自定义类加载器。
图解如下:
dd
  需要注意的是,Java虚拟机规范并没有强制要求实现这三种类型的类加载器,但是大多数Java虚拟机实现都会提供这三种类型的类加载器。

特点

JVM类加载器有以下特点

  • 分层:JVM类加载器分为多个层次,每个层次都有自己的类加载器和父级类加载器。开发者可以创建自定义类加载器,并将其添加到任何级别的层次中。
  • 隔离:每个类加载器都有自己的命名空间,其中包含由其加载的所有类。因此,不同类加载器可以加载具有相同名称的类,但这些类的实例不会相互干扰。
  • 动态性:开发者可以创建自定义类加载器来动态地加载Java类。例如,Web服务器可以使用自定义类加载器来加载Web应用程序所需的Java类。
  • 缓存:JVM会缓存已加载的类的元数据信息,以便在再次需要时快速访问。

类加载机制

动态类加载

类名称空间

判断类是否“相等”?
  任意一个类,都由加载它的类加载器和这个类本身一同确立其在 Java 虚拟机中的唯一性,每一个类加载器,都有一个独立的类名称空间。
  因此,比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个 Class 文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那么这两个类就必定不相等。
  这里的“相等”,包括代表类的 Class 对象的 equals() 方法、isInstance() 方法的返回结果,也包括使用 instanceof 关键字做对象所属关系判定等情况。

性能优化

  1. 减少类加载器的数量:在应用程序中使用过多的类加载器会降低性能,因此应该尽量减少类加载器的数量。
  2. 使用缓存:对于已经加载的类,可以使用缓存技术进行存储和管理,避免重复加载同一个类。Java中的类加载器可以缓存已经加载的类,因此使用缓存可以减少加载时间和提高性能。
  3. 使用类预加载技术:对于需要经常使用的类,可以使用类预加载技术,通过预先加载类来提高类的访问速度。可以使用静态变量或者单例模式等技术来预加载类。
  4. 优化类的加载顺序:对于应用程序中频繁使用的类,可以优化它们的加载顺序,使其先加载,从而减少应用程序的启动时间。
  5. 使用轻量级类库:Java中有许多轻量级的类库,可以提高应用程序的性能。这些类库通常具有更小的代码库和更快的加载速度,因此可以提高应用程序的性能。
  6. 使用JIT优化:Java HotSpot虚拟机中自带JIT编译器,可以将字节码编译为本地机器码,从而提高性能。

  参考文献
   虚拟机规范
   深入理解Java虚拟机
   openjdk

  如果喜欢的话,欢迎 🤞关注 👍点赞 💬评论 🤝收藏  🙌一起讨论
  你的支持就是我✍️创作的动力!					  💞💞💞

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2023年10月17日
下一篇 2023年10月17日

相关推荐