JVM类加载机制

JVM类加载机制

类加载过程

详细链接: https://www.processon.com/view/link/61e31970e0b34d1be7f8ac96

类加载过程.png

  • ClassLoader.loadClass()的类加载过程
    • 加载: 从磁盘上将.class的字节码文件加载到JVM内存中去,此时会做一些简单的校验,校验通过后,会生成一个java.lang.Class对象,作为这个类各种数据再方法区的入口
    • 验证: 校验字节码文件的正确性,看看是否符合JVM字节码规范,比如魔数,主次版本号等
    • 准备: 将类中的静态变量分配内存并且赋默认值
    • 解析: 将符号引用(比如方法名)转变为直接引用(JVM内存地址),这就是所谓的静态链接的过程
      • 静态链接: 类加载期间,将符号引用转变为直接引用
      • 动态链接: 程序运行期间,将符号引用转变为直接引用,比如方法中调用方法,JVM解析的时候会对被调用的方法名指向一个内存地址,通过这个地址找到对应的方法,最常见的就是多态,有不同的实现,只有到运行的时候才知道
    • 初始化: 对类的静态变量初始化为指定值,执行静态代码块
  • 类被加载到方法区中包含
    • 运行时常量池
    • 类型信息
    • 字段信息
    • 方法信息
    • 类加载器的引用
    • 对应class实例的引用
  • 注意: 类加载机制是懒加载,部署war包使用时才会加载,静态代码块比构造函数先执行,类没加载完,不会调用构造函数

类加载器和双亲委派机制

类加载器

  • 引导类加载器(BootStrap): 加载jre/lib目录下的核心类库

  • 拓展类加载器(Ext): 加载支撑JVM运行的jre/lib/ext目录下的jar

  • 应用程序类加载器(App): 加载classpath路径下的类包,主要是加载用户自己写的类

  • 自定义类加载器: 加载用户自定义路径下的类。特殊需要的时候才自定义类加载器,比如Tomcat会自定义类加载器,默认是应用程序加载器

  • sum.misc.Launcher可以理解为所有类的父类加载器,C++先初始化Launcher类后,在通过此类生成拓展类、应用程序类加载器等

  • 问题: 为什么引导类加载器不是Launcher类生成的

    • 因为引导类加载器是由C++直接生成的对象

类加载器初始化过程

  • 创建JVM启动器实例: sun.misc.Launcher,此类为单例模式,保证只有一个实例
  • Launcher类创建两个类,ExtClassLoader和AppClassLoader
  • JVM默认使用Launcher的ClassLoader方法返回的加载器AppClassLoader的实例加载我们的应用程序

双亲委派机制

双亲委派机制.png

  • 当应用程序类加载器加载某类时,如果没有找到,就会向上让扩展类加载器去加载
  • 如果扩展类加载器也没有该类,就会继续向上让引导类加载器去加载
  • 如果引导类加载器也没有该类,那么就向下继续委托
  • 如果都没有找到,那么就让应用程序类加载器去加载
为什么要先用应用程序类加载器去加载代码,而不是直接用引导类加载器
  • 因为大部分的类都是用户自己定义编写的,也就是大部分的类文件都存放在应用程序类加载器的指定类路径下,如果不从这里开始会导致效率降低
什么是双亲委派机制
  • 双亲委派机制就是加载某个类时先委托父加载器去寻找目标类,找不到再委托上层父加载器,如果所有父加载器都没有自己类路径下找到目标类,那么就会交给最开始的类加载器去加载该目标类
为什么要设计双亲委派机制
  • 双亲委派机制可以避免类的重复加载
  • 沙箱安全机制,保证核心类不被篡改

全盘委托机制

  • 全盘委托是指当一个ClassLoder装载一个类时,除非显示的使用另外一个ClassLoder,该类所依赖及引用的类也由这个ClassLoder载入

如何自定义类加载器

  • 代码思路
    • 继承java.lang.ClassLoader类
    • 重写ClassLoader.findClass()方法,此方法通过IO读取自定类文件路径
    • 重写ClassLoader.loadClass()方法,加载类

打破双亲委派机制

  • 加载一个类,不使用父加载器,直接由自定义类加载器加载类
  • 代码思路
    • 重写ClassLoader.loadClass()方法后
    • 在里面调用父加载器的方法处添加判断逻辑,如果是自定义类路径,就调用自定义的findClass方法
Tomcat为什么要打破双亲委派机制
  • 对于一个web容器来说,可能需要部署多个应用程序,不同的应用程序可能依赖相同类库的不同版本,但是双亲委派机制已经实现了避免重复类加载,因此要保证每个版本的类库是独立的,要保证相互隔离
  • 部署在同一个web容器中相同类库的版本可以共享,否则多个应用程序此时都是同一类库的版本,会导致进行加载多次,浪费资源
  • 处于安全方面考虑,Tomcat也有自己的类库,也需要进行隔离处理,否则会导致与应用程序的类库混淆
  • 每个jsp对应一个类加载器,这样是为了方便热部署
Tomcat这种类加载机制是否违背了双亲委派机制
  • 很显然是的,Tomcat为了实现隔离性,每个webappClassLoader加载自己目录下的类文件,不会传递给父加载器,打破了双亲委派机制
  • 首先自己尝试去加载某类,如果找不到再代理给父加载器,其目的是优先加载web应用自己定义的类,它父类加载器就是AppClassLoader
  • web应用是通过Class.forName()调用交给系统类加载器的,因为Class.forName的默认类加载器是系统类加载器
Tomcat怎么实现热加载
  • 单独用一个线程时刻去监听jsp文件路径下文件夹的变动,比如说1s监听一次,如果有变动,把之前的类加载器置空,再重新赋值最新的类加载器,之前的等待gc回收
Tomcat类加载图

Tomcat自定义类加载器-打破双亲委派机制.png

相关推荐

  1. JVM机制

    2024-03-10 02:58:05       13 阅读
  2. JVM机制(中)

    2024-03-10 02:58:05       42 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-10 02:58:05       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-10 02:58:05       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-10 02:58:05       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-10 02:58:05       20 阅读

热门阅读

  1. RK android11 user打开adb调试功能

    2024-03-10 02:58:05       20 阅读
  2. chatgpt

    2024-03-10 02:58:05       24 阅读
  3. 算法之简单排序算法“选择排序”(python)

    2024-03-10 02:58:05       20 阅读
  4. webpack 打包后,图片加载错误

    2024-03-10 02:58:05       21 阅读
  5. 单例九品--第七品

    2024-03-10 02:58:05       21 阅读
  6. ChatGPT网络安全风险治理

    2024-03-10 02:58:05       24 阅读
  7. [渗透教程]-200-网络安全基本概念

    2024-03-10 02:58:05       20 阅读