JVM类加载机制

425 阅读3分钟

JVM类加载机制

前言

一个对象在创建过程中,首先要判断这个类是否加载了,只有加载了我们才可以给他分配相应的内存。加载器并不是很神秘,加载器就是一个类。下面就让我们来一起了解一下什么是JVM的类加载机制。

01JVM类加载机制.png

类加载过程

类加载主要包含加载、验证、准备、解析、初始化、使用、卸载过程。

加载:使用到该类时,读入该类的class文件到内存中,并且在内存中会生成一个该类的java.lang.Class对象,作为这个类各种数据的访问入口。

验证:检验字节码文件的正确性。

准备:给类的静态变量分配内存,赋予默认值。

解析:将符号引用替换为直接引用(指向内存的地址)。

初始化:将类的静态变量赋予真正的值。

类加载器

类加载器并没有这么神秘,他其实就是一个类,主要分为以下几种类加载器。

  • 引导类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如rt.jar、charsets.jar等

  • 扩展类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包

  • 应用程序类加载器:负责加载ClassPath路径下的类包,主要就是加载你自己写的那些类

  • 自定义加载器:负责加载用户自定义路径下的类包

    在我们执行代码的时候,首先由c++创建引导类加载器,然后再由JVM启动实例Launcher创建扩展类加载器、应用程序类加载器,由应用程序类加载器加载我们自定义的加载器。下面我们看一下Launcher构造类加载器的代码。

1637812524(1).jpg 可以看到扩展类加载器父类没有设置,应用程序加载器父类为扩展类加载器。

双亲委派机制

在类加载过程中,有一个双亲委派机制,大致思想就是加载的类的时候,先让父类加载,父类加载不了让子类加载。

未命名文件 (6).png

为什么这样设计,主要出于以下两个原因:

  • 防止java核心库被自定义的加载器加载,试想一下,如果任何一个类加载器都可以加载java核心库的类,例如String,那么必定会带来安全问题,也会导致java核心库被修改。
  • 防止一个类被多个加载器加载。

构造自己的类加载器

下面就让我们来自己构造一个类加载器。

1637823926(1).jpg

主要要自己构建test/com/test/Test目录,并把Test.class文件放到该目录下,自定义类加载器的核心就是重写findClass方法,指定加载的目录。

Tomcat打破双亲委派机制

为什么tomcat会打破双亲委派机制?因为一个tomcat可能会有多个服务,虽然我们建议一个tomcat部署一个服务,每个服务用到的框架版本可能不一样,如果采用双亲委派机制,就会无法统一版本,因此tomcat打破了双亲委派机制,主要就是重写ClassLoader的loadClass方法。