JVM | 类加载是怎么工作的

news2024/11/16 6:05:20

类加载是怎么工作的

  • 引言
  • 类加载器工作原理 | 城市建设过程
      • 1. 类加载器加载类前过程
        • JVM进程启动 | 建筑工程立项
        • Bootstrap类加载器创建扩展和应用类加载器 | 高级工程师的两位得力助手
      • 2. 类加载器加载类后过程
        • 应用类加载器加载Building
        • 链接过程(验证,准备,解析)
        • 初始化过程
        • 使用过程
        • 卸载过程
  • 解决建筑过程中出现的问题
      • 1. floorCount为什么没被初始化?
      • 2. 高级工程师为什么不直接把活派给应用类加载器而是先给扩展类加载器?
        • 高级工程师的决定他人不能改变 | 保证Java核心API不被篡改
        • 避免出现重复的工作量 | 防止类的重复加载
      • 3. 为什么你写了main()方法,程序就可以运行了?
  • 有哪些建筑工人 | 类加载器
      • 引导类加载器(Bootstrap ClassLoader)
      • 扩展类加载器(Extension ClassLoader)
      • 应用类加载器(Application ClassLoader)
  • 常见面试题
  • 总结
  • 后续

引言

在程序世界的大海洋中,就像是构建一切的基石。它们是构建Java应用的原材料,类加载器则是这个世界的建筑工人。他们负责将构建城市所需的材料搬运到工地(JVM)。了解类加载器的工作原理,就像了解城市建设的过程,能够让我们更好地理解和控制程序的运行。现在,让我们深入探索JVM的类加载器,解析它的奥秘,开启这趟神奇的旅程吧!


如果说并发编程是指挥交通的艺术,那么了解JVM就是为城市添砖加瓦的艺术。我们来看下究竟是什么样的。

类加载器工作原理 | 城市建设过程

首先,我们编写了一个类:

public class Building {
    public Building() {
        System.out.println("建筑蓝图已被创建! 我们可以添砖Java了");
    }
    private static int constructionYear = 2023;
    private int floorCount;

    public Building(int floors) {
        this.floorCount = floors;
    }

    public void setFloorCount(int floors) {
        this.floorCount = floors;
    }

    public int getFloorCount() {
        return this.floorCount;
    }

    public static int getConstructionYear() {
        return constructionYear;
    }
    
    public static void main(String[] args) {
        new Building();
    }
}

类中有一个main()方法的程序入口点。我们运行一下:

Connected to the target VM, address: '127.0.0.1:9888', transport: 'socket'
建筑蓝图已被创建! 我们可以添砖JavaDisconnected from the target VM, address: '127.0.0.1:9888', transport: 'socket'

Process finished with exit code 0

好,没什么问题。你是否好奇当我们在IDE绿色的小箭头点击run ‘Building.main()’之后,底层到底发什么什么?嗯...有问必答,我们接着看。


1. 类加载器加载类前过程

我还是结合上面的例子为你讲解,请你仔细思考它们的对应关系。我们开始吧~

JVM进程启动 | 建筑工程立项

当我们在IDE绿色的小箭头点击run ‘Building.main()’ 其实IDE会进行两个步骤:

  1. 编译:IDE会先使用javac编译器,将你的.java源文件编译成.class字节码文件。这一步骤通常是在后台进行的,你通常不会看到任何有关编译的消息,除非出现编译错误。(往往这个时候程序员就要挠掉不少头发)

  2. 运行:编译完成后,IDE会使用java命令启动JVM进程,然后载入并执行相应的.class文件中的main方法。

搞懂这两个步骤,我们接着往下说。

首先,当你在运行java Building这个指令时,就好比发出了开工命令。JVM就像一位总承包商,控制着一位特殊的工人,也就是Bootstrap类加载器。这位工人的工作是从核心材料库($JAVA_HOME/jre/lib)中取出构建这座大楼所需的基本原材料,这些基本材料包括了Java的核心类库。

Bootstrap类加载器创建扩展和应用类加载器 | 高级工程师的两位得力助手

Bootstrap类加载器,像一位高级工程师,接下来派遣了另外两位工人,他们是扩展(ext)类加载器应用(app)类加载器。扩展类加载器的任务是从扩展材料库$JAVA_HOME/jre/lib/ext获取扩展材料。应用类加载器的任务是从建筑工地周围(系统类路径CLASSPATH)收集所需的特定材料。

至此,类加载器加载类前过程已经完成了,我们接着往后看。


2. 类加载器加载类后过程

应用类加载器加载Building

当你(雇主)告诉高级工程师(Bootstrap类加载器)你需要一个名为Building 的设计蓝图,这个时候高级工程师就可以派出它的得力助手扩展类加载器了,但是扩展类加载器发现Building不是它的职责范围,于是把活交给应用类加载器,他刚好知道在哪里可以找到Building.class这个特定的建筑蓝图。他会沿着系统类路径,寻找到这个类文件,并将其内容(类的字节码)搬运到JVM中。这个过程就好像是将建筑蓝图放到了JVM的工地上。

链接过程(验证,准备,解析)

当Building类的字节码被搬运到JVM后,总承包商会委托工人们对这些原材料进行处理。他们会检查材料(验证),然后对constructionYear 材料进行预处理先把它设置为0(准备),你看:

private static int constructionYear = 0;

最后将它们组合在一起(解析),把JVM将常量池中的符号引用替换为直接引用。这个过程就好比按照蓝图的要求,将砖块、水泥等材料准备好并组装起来。

初始化过程

紧接着就开始真正的施工了。工人们按照Building类的main方法(也就是建筑的蓝图)开始构建大楼。在这个例子中,它会创建一个新的Building对象。并且静态变量constructionYear在初始化阶段会被初始化为2023,你看:

private static int constructionYear = 2023;

这就好比工人们按照蓝图上的指示,开始把砖块、水泥等材料搭建起来。

使用过程

一旦建筑物(也就是Building对象)被创建出来,就可以开始使用了。在这个例子中,当Building对象被创建时,它的构造函数会被调用,打印出”建筑蓝图已被创建! 我们可以添砖Java了“。

卸载过程

当大楼(也就是Building对象)不再被使用,或者建筑工地(也就是JVM)需要关闭时,这座大楼就会被拆除。这个过程由JVM的垃圾回收器负责,它会清理掉不再需要的Building对象。当没有任何类加载器引用这个Building类时,这个类也将被卸载。这就好比当大楼不再需要,或者工地需要关闭时,大楼会被拆除,蓝图(也就是Building.class文件)也会被收回。


解决建筑过程中出现的问题

不知道你有没有发现,我在描述初始化的过程中并没有提到floorCount变量,那这个材料就不初始化了吗?还有,为什么一开始高级工程师不直接把活派给应用类加载器而是先给扩展类加载器?还有,为什么写了main()方法,程序就可以运行了?好好好,我一个一个来为你解答

1. floorCount为什么没被初始化?

它们会在创建对象的时候(也就是新建Building对象时)被初始化。实例变量floorCount是属于对象的,每个对象都有一份独立的副本,它们的生命周期随着对象的创建和销毁而开始和结束。

2. 高级工程师为什么不直接把活派给应用类加载器而是先给扩展类加载器?

因为高级工程师很聪明,他知道有一种双亲委派机制可以提高效率,怎么提高效率?

高级工程师的决定他人不能改变 | 保证Java核心API不被篡改

例如: 自己写的java.lang.String.class类不会被加载,这样便可以防止核心
API库被随意篡改

避免出现重复的工作量 | 防止类的重复加载

当父类加载器已经加载了某个类时,子加载器就不会再加载,避免了重复加载。

当然还有不少优点:防止Java类库的冲突,节省内存空间… 这里就不赘述了。

3. 为什么你写了main()方法,程序就可以运行了?

这是由类加载器内部运行机制决定的,你可以看下流程:
在初始化完成后,JVM会查找类中的 main 方法。 main 方法的标准声明应为: public static void main(String[] args)。这个方法是静态的(即与类关联,而不是与对象关联),因此JVM可以在不创建类的实例的情况下调用它。一旦找到 main 方法,JVM就会执行它。程序的执行流程就从 main 方法开始。


有哪些建筑工人 | 类加载器

上面已经提到,除了引导类加载器(BootStrap)之外,还有扩展类加载器(Ext) 和应用类加载器(App),我们在这里着重再介绍下吧~

引导类加载器(Bootstrap ClassLoader)

引导类加载器是最顶级的类加载器,它主要负责加载Java的核心类库,例如java.lang.*,java.util.*等。这些类库的位置通常在JDK的jre/lib/rt.jar中。引导类加载器是由C++编写的,我们在Java中是无法获取它的引用的。引导类加载器是其他类加载器的父加载器

扩展类加载器(Extension ClassLoader)

扩展类加载器是引导类加载器的子类,它负责加载JDK的扩展类库,这些类库通常位于JDK的jre/lib/ext/目录下或者由系统变量java.ext.dirs指定的目录下。扩展类加载器是由Java编写的,其具体实现类是sun.misc.Launcher$ExtClassLoader

应用类加载器(Application ClassLoader)

应用类加载器是扩展类加载器的子类,也是我们通常接触到的默认的类加载器。它负责加载用户路径(ClassPath)上所指定的类库。这个路径可以通过环境变量CLASSPATH设置,也可以通过java命令的-classpath或者-cp参数设置。应用类加载器的实现类也是sun.misc.Launcher$AppClassLoader

每当子类加载器需要加载类时,首先会委托父类加载器进行加载,直到最顶层的引导类加载器。如果父类加载器无法加载该类,才会由子类加载器自己进行加载。

为了你加深对它们的印象,我了一张关于这三个的类加载器树图,你可以暂停看一下:
在这里插入图片描述


常见面试题

  1. 什么是类加载器(ClassLoader),类加载器有哪些?
  2. 能简单描述一下类的生命周期吗?它们在JVM中的状态有哪些?
  3. 什么是双亲委派模型?这种模型有什么优点?
  4. 请解释一下引导类加载器、扩展类加载器和应用类加载器的区别?

总结

好,我们来做个总结。作为JVM的开篇,还是老样子,我为你构建一个建筑工地的世界。基于这个世界,我为你讲解了类加载器的工作原理。并且为你解答了一些类加载器过程中遇到的问题,带你重新回顾了一下,本篇文章的三位主人公,它们分别是:引导类加载器,扩展类加载器,应用类加载器。最后我留了几道面试题,不知道你是否都能答上来呢。

后续

既然高级工程师和两位建筑工人已经把事情都划分完了,那么其它工人怎么办?类加载器可以自己定义吗?如何实现? 什么情况下需要使用自定义类加载器?你是否了解ServiceLoader和SPI机制?后面一篇我会回答这些问题,敬请期待。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/800927.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Huge and Efficient! 一文了解大规模预训练模型高效训练技术

本文分为三部分介绍了大模型高效训练所需要的主要技术,并展示当前较为流行的训练加速库的统计。文章也同步发布在AI Box知乎专栏(知乎搜索 AI Box专栏),欢迎大家在知乎专栏的文章下方评论留言,交流探讨! 引…

计算机图形学十四路径追踪与渲染方程

路径追踪(Path Tracing)与渲染方程(Render Equation) 简介 利用路径追踪我们可以实现比whitted-style ray tracing更好的全局光照(GI)效果。它的理论基础是渲染方程,最开始由吉姆卡吉亚&#…

066、故障处理之热点问题

为什么要解决热点 分布式架构中各个组件的理想状态:资源利用率相对均衡 形成写热点的原因 高频访问的小表SQL执行计划不合理具有顺序增长属性的索引扫描 数据组织模型 例如数据是序列递增,则有可能数据全部都集中一个region上 ,或者集中…

什么是等保定级?

TOC 一、等保评测介绍 1.1 等保定级目的 网络安全等级保护介绍:目的就是涉及民生问题的信息系统,要按照影响,提前划定等级 实施网络安全保护 信息系统:就是保护的系统,比如 魔幻的 健康码系统安全产品:健…

【lesson5】linux常见权限问题

文章目录 目录权限umask粘滞位 目录权限 先来思考一个问题: 进入一个目录需要什么权限呢? 由上图我们可以得知,进入目录需要x权限,那么没有r和w权限是什么情况呢? 从图中我们可以得知没有r权限不能查看目录里面的内容&#xff…

基于STM32设计的智能教室管理系统

前言 本文介绍了一个智慧教室的设计,该设计由电器设备控制系统、环境检测系统和考勤系统三大模块构成。通过使用STM32微处理器和物联网电器设备控制中心,实现对教室内风扇、照明灯和窗帘等电器设备的智能化统一控制与运行。同时,环境检测系统可以实时监测环境光强、温度、湿…

模型调参及优化

调参 调权重参数,偏置参数 训练数据集用来训练参数w,b 调超参数 验证数据集用来选择超参数学习率lr,隐藏层大小等 如何调参 当泛化误差和训练误差都没有降下去说明欠拟合;当训练误差降下去,但泛化误差出现上升形式&…

33. 本地记事本

本地记事本 html部分 <button class"add"><i class"iconfont icon-jiahao"></i> </button>css部分 *{margin: 0;padding: 0; } body{background-color: #7bdaf3;display: flex;padding-top: 3rem;flex-wrap: wrap; } .add{pos…

Vue2基础一、快速入门

零、文章目录 Vue2基础一、快速入门 1、Vue 概念 &#xff08;1&#xff09;为什么学 前端必备技能 岗位多&#xff0c;绝大互联网公司都在使用Vue 提高开发效率 高薪必备技能&#xff08;Vue2Vue3&#xff09; &#xff08;2&#xff09;Vue是什么 **概念&#xff1a;…

第二届“鼎信杯”榜单发布,麒麟信安荣获“优秀技术支撑奖”

由中国电子信息产业发展研究院、北京市海淀区人民政府主办&#xff0c;中国软件评测中心&#xff08;工业和信息化部软件与集成电路促进中心&#xff09;、中关村科学城管委会和北京市国际技术贸易协会承办的“2023 鼎信杯信息技术发展论坛”日前在北京举办。麒麟信安受邀参加主…

和鲸 ModelWhale 与麒麟系统适配认证,打造自主安全、性能可靠的信创 AI 基础软件

发展信创&#xff0c;解决核心技术的自主可控问题&#xff0c;是我国产业升级和数字经济发展过程中的重要命题。信创产业链主要由基础硬件、基础软件、应用软件、信息安全及云计算平台等几部分组成&#xff0c;拥抱信创国产化需要各厂商聚力共创生态&#xff0c;增强自身产品的…

JSONPath提取器案例详解

jsonpath语法 $ 表示根节点&#xff0c;也是所有jsonpath表达式的开始 . 表示获取子节点 .. 表示获取所有符合条件的内容 * 代表所有的元素节点 [] 表示迭代器的标示&#xff08;可以用于处理下标等情况&#xff09; [,] 表示多个结果的选择 ?() 表示过滤操作 表示当前节点一…

【QT】Day1

1. 收到实现登录框 要求&#xff1a; 1、登录窗口更改标题、图标 2、设置固定尺寸、并给定一定的透明度 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QDebug> //信息调试类&#xff0c;用于打印输出的 #include <QIcon>…

windows命令行

参考:https://blog.csdn.net/u014419722/article/details/130427423 1、 创建文件夹&#xff08;mkdir或md&#xff09; 创建单个文件&#xff1a;mkdir cmd_test 创建二级文件&#xff1a;mkdir cmd_test\456\123 创建多个文件&#xff1a;mkdir cmd_test\000 cmd_test\111 2…

【js】javascript中base64转file、file压缩图片:

文章目录 一、效果图:二、实现代码: 一、效果图: 二、实现代码: /*** base64转file* param {string} urlData base64格式图片* returns */ export function base64ConvertFile(urlData) {if (typeof urlData ! string) {this.$toast("urlData不是字符串")return;}va…

IDEA 模块不加载依旧是灰色 没有变成小蓝色的方块

Settings > Build, Execution, Deployment > Build Tools > Maven > Ignored Files下降对应的模块勾选掉 但通常在Maven的配置中&#xff0c;您会找到一个名为“ignoredFiles”的列表&#xff0c;其中包含被忽略的文件和目录。您可以通过取消选中所需的文件或目录…

腾讯云—自动挂载云盘

腾讯云&#xff0c;稍微麻烦了点。 腾讯云服务器&#xff0c;镜像为opencloudos 8。 ### 1、挂载云盘bash #首先通过以下命令&#xff0c;能够看到新的数据盘&#xff0c;如果不能需要通过腾讯云控制台卸载后&#xff0c;重新挂载&#xff0c;并重启服务器。 fdisk -l#为 /dev…

【iVX】低代码未来发展趋势

未来低代码开发将更加注重用户体验、集成能力、自动化水平和移动支持。同时&#xff0c;应用场景也将进一步扩展&#xff0c;安全与可靠性也将得到更大程度的关注和加强。这些发展方向将进一步推动低代码开发在各个行业和领域的广泛应用和发展。 增强设计能力&#xff1a;低代码…

RFID技术如何赋能化工行业?

化工生产是指在化工行业中&#xff0c;将原材料经过一系列的物理、化学或生物过程转化为最终产品的过程。RFID技术在化工行业中提供了实时跟踪、自动化控制、安全监测和环境管理等方面的帮助&#xff0c;对于提高生产效率、质量控制和安全性具有重要的意义。我们通过典型的化工…

【100天精通python】Day18:python程序异常与调试_常用程序调试方式与技巧,如何将调试代码与正式代码分开

一 程序调试 在Python中&#xff0c;调试是指识别和修复程序中的错误和问题。 调试是程序开发过程中必不可少的一部分&#xff0c;合理利用调试工具和技术可以提高程序开发的效率和质量。Python提供了几种用于调试的工具和技术&#xff0c;帮助开发者找出程序中的bug并进行修复…