【JVM】类加载

1. 类加载过程

Java虚拟机(JVM)的 类加载 过程是将字节码文件(.class文件)从存储设备加载到内存,并为其创建相应的类对象的过程。类加载是Java程序运行的基础,保证了程序的动态性和安全性。JVM的类加载过程主要分为五个阶段:加载(Loading)连接(Linking)初始化(Initialization)使用(Using)卸载(Unloading)。其中,连接阶段又分为验证准备解析三个子阶段。

1.1 加载(Loading)

在这个阶段,JVM通过类加载器将类的字节码从文件系统或网络等资源中加载到内存,并创建一个java.lang.Class对象来表示这个类。加载阶段包括以下几步:

  • 通过类的全限定名查找并读取类的字节码文件(通常是.class文件)。
  • 将字节码数据加载到JVM的内存中,并在方法区中生成类的运行时数据结构。
  • 在堆中生成Class对象,作为类的字节码数据的访问入口。

注意:Java的类是按需加载的,只有在程序第一次使用某个类时,才会触发类的加载过程。

1.2 连接

连接阶段的目的是确保类可以被正确使用,它分为三个子阶段:验证准备解析

验证(Verification)

图引用:[1]

验证是为了确保被加载的类的字节码是符合JVM规范的,并且不会破坏JVM的安全性。主要包括:

  • 文件格式验证:检查.class文件的格式是否符合规范。
  • 元数据验证:验证类中的元数据(如类的字段、方法)是否合法。
  • 字节码验证:确保类的字节码操作符号是合法的,例如跳转指令不会跳到无效位置,数据类型操作正确等。
  • 符号引用验证:检查解析时,符号引用是否能够解析到实际的类、字段或方法。
准备(Preparation)

准备阶段是为类的静态变量分配内存,并将其初始化为默认值。注意,此时的初始化并不是为静态变量赋值,而只是分配内存和设置默认值(例如,int类型的默认值是0boolean的默认值是false,引用类型的默认值是null)。

public static int a = 10;

 在准备阶段,a的值为默认的0,而不是10。赋值操作将在初始化阶段进行。

解析(Resolution)

解析阶段是将类的符号引用转换为直接引用。符号引用是编译时期的一种表示方式,而直接引用是运行时的真实地址或偏移量。解析过程主要包括:

  • 类或接口解析:将符号引用的类或接口解析为内存中的实际类或接口。
  • 字段解析:将符号引用的字段解析为具体类的字段。
  • 方法解析:将符号引用的方法解析为实际的方法地址。
  • 接口方法解析:解析接口中的方法引用。

《深入理解 Java 虚拟机》7.34 节第三版对符号引用和直接引用的解释如下[1]:

解析过程可以在连接的解析阶段完成,也可以在类使用时延迟进行(例如动态绑定)。

1.3 初始化(Initialization)

初始化阶段是类加载过程中唯一一个会执行代码的阶段。在这个阶段,JVM执行类的静态代码块静态变量的初始化赋值操作。

初始化阶段,Java 虚拟机真正开始执行类中编写的Java 程序代码,将主导权移交给应用程序。初始化阶段就是执行类构造器方法的过程。

例如:

public static int a = 10;
static {a = 20;
}

在初始化阶段,a将被赋值为20

1.4. 使用(Using)

在类初始化之后,该类可以被程序使用。程序可以通过调用类的静态方法、访问静态字段、创建类实例等方式使用类。

1.5. 卸载(Unloading)

类的卸载是指当类不再被使用时,JVM将其从内存中移除。类的卸载通常由垃圾回收器完成,当没有任何类加载器引用该类的Class对象,并且类的实例也不再存在时,类才会被卸载。

2. 双亲委派模型

2.1 类加载器

Java的类加载器分为三大类,分别是:

  1. 引导类加载器(Bootstrap ClassLoader)

    • 负责加载Java核心库(如rt.jar中的类),例如java.lang.Stringjava.util.List等。这是JVM自身实现的类加载器,位于JVM的本地代码中,开发者无法直接操作引导类加载器。
    • 引导类加载器从JRE安装目录下的lib目录或-Xbootclasspath指定的路径中加载类。
  2. 扩展类加载器(Extension ClassLoader)

    • 加载JVM扩展库,一般是加载位于JRE/lib/ext目录下的类或由java.ext.dirs系统属性指定的目录下的类。开发者可以访问扩展类加载器。
    • 该加载器是由sun.misc.Launcher$ExtClassLoader实现的。
  3. 应用程序类加载器(Application ClassLoader)

    • 加载应用程序类路径(CLASSPATH)中的类,负责加载用户编写的代码。开发者也可以自定义类加载器来代替应用程序类加载器。
    • 该加载器是由sun.misc.Launcher$AppClassLoader实现的。它是我们编写的Java应用程序最常使用的类加载器。

除了 BootstrapClassLoader 是 JVM 自身的一部分之外,其他所有的类加载器都是在 JVM 外部实现的,并且全都继承自 ClassLoader抽象类。这样做的好处是用户可以自定义类加载器,以便让应用程序自己决定如何去获取所需的类。

每个 ClassLoader 可以通过getParent()获取其父 ClassLoader,如果获取到 ClassLoadernull的话,那么该类是通过 BootstrapClassLoader 加载的

2.2 双亲委派模型

如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最 终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无 法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。

双亲委派模型的实现代码非常简单,逻辑非常清晰,都集中在 java.lang.ClassLoaderloadClass() 中,相关代码如下所示。 

protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException
{synchronized (getClassLoadingLock(name)) {//首先,检查该类是否已经加载过Class c = findLoadedClass(name);if (c == null) {//如果 c 为 null,则说明该类没有被加载过long t0 = System.nanoTime();try {if (parent != null) {//当父类的加载器不为空,则通过父类的loadClass来加载该类c = parent.loadClass(name, false);} else {//当父类的加载器为空,则调用启动类加载器来加载该类c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {//非空父类的类加载器无法找到相应的类,则抛出异常}if (c == null) {//当父类加载器无法加载时,则调用findClass方法来加载该类//用户可通过覆写该方法,来自定义类加载器long t1 = System.nanoTime();c = findClass(name);//用于统计类加载器相关的信息sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {//对类进行link操作resolveClass(c);}return c;}
}

 双亲委派模型的优点

1. 避免类的重复加载:同一个类只会由一个类加载器加载一次,避免了类的重复加载,保证了类加载的唯一性。

2.保证Java核心类的安全:如果允许自定义类加载器加载和替换Java核心类库中的类,例如java.lang.String,开发者可以定义一个具有相同全限定名(包名和类名)的自定义类。这样,当系统中调用String类时,可能会不小心使用开发者自定义的String类,导致系统行为出现不一致,甚至引发严重的安全问题。

为了防止这种情况,Java采用双亲委派机制。根据双亲委派模型,所有类加载器在尝试加载类时,首先会委派给父加载器,最终到达最顶层的引导类加载器。引导类加载器专门负责加载JDK中的核心类库,并确保这些核心类库的加载不可被覆盖。

3. 破坏双亲委派模型

自定义加载器的话,需要继承 ClassLoader

如果我们不想打破双亲委派模型,就重写 ClassLoader 类中的 findClass() 方法即可,无法被父类加载器加载的类最终会通过这个方法被加载。

但是,如果想打破双亲委派模型则需要重写 loadClass() 方法。这是因为:类加载器在进行类加载的时候,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成(调用父加载器 loadClass()方法来加载类)。

例如,Tomcat中的类加载器架构打破了双亲委派模型,每个Web应用都有自己的类加载器,并且每个应用之间的类加载是相互隔离的。


引用:

[1]JavaGuide(javaguide.cn):https://javaguide.cn/java/jvm/class-loading-process.html

[2]《深入理解 Java 虚拟机》

[3]Chapter 5. Loading, Linking, and Initializing:
Chapter 5. Loading, Linking, and Initializing

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人工智能 | 基于ChatGPT开发人工智能服务平台

简介 ChatGPT 在刚问世的时候&#xff0c;其产品形态就是一个问答机器人。而基于ChatGPT的能力还可以对其做一些二次开发和拓展。比如模拟面试功能、或者智能机器人功能。 模拟面试功能包括个性化问题生成、实时反馈、多轮面试模拟、面试报告。 智能机器人功能提供24/7客服支…

将阮一峰老师的《ES6入门教程》的源码拷贝本地运行和发布

你好同学&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏、评论和关注。 阮一峰老师的《ES6入门教程》应该是很多同学学习 ES6 知识的重要参考吧&#xff0c;应该也有很多同学在看该文档的时候&#xff0c;想知道这个教程的前端源码是怎么实现的&#xff0c;也可能有同学下载…

esp32 wifi 联网后,用http 发送hello 用pc 浏览器查看网页

参考chatgpt Esp32可以配置为http服务器&#xff0c;可以socket编程。为了免除编写针对各种操作系统的app。完全可以用浏览器仿问esp32服务器&#xff0c;获取esp32的各种数据&#xff0c;甚至esp的音频&#xff0c;视频。也可以利用浏览器对esp进行各种操作。但esp不能主动仿…

【医学半监督】置信度指导遮蔽学习的半监督医学图像分割

摘要: 半监督学习(Semi-supervised learning)旨在利用少数标记数据和多数未标记数据训练出高性能模型。现有方法大多采用预测任务机制,在一致性或伪标签的约束下获得精确的分割图,但该机制通常无法克服确认偏差。针对这一问题,本文提出了一种用于半监督医学图像分割的新…

【C++笔记】C++编译器拷贝优化和内存管理

【C笔记】C编译器拷贝优化和内存管理 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】C编译器拷贝优化和内存管理前言一.对象拷贝时的编译器优化二.C/C内存管理2.1练习2.2 C内存管理方式2.3 operator new与operator…

分布式锁优化之 使用lua脚本改造分布式锁保证判断和删除的原子性(优化之LUA脚本保证删除的原子性)

文章目录 1、lua脚本入门1.1、变量&#xff1a;弱类型1.2、流程控制1.3、在lua中执行redis指令1.4、实战&#xff1a;先判断是否自己的锁&#xff0c;如果是才能删除 2、AlbumInfoApiController --》testLock()3、AlbumInfoServiceImpl --》testLock() 1、lua脚本入门 Lua 教程…

长亭WAF绕过测试

本文的Bypass WAF 的核心思想在于&#xff0c;一些 WAF 产品处于降低误报考虑&#xff0c;对用户上传文件的内 容不做匹配&#xff0c;直接放行 0、环境 环境&#xff1a;两台服务器&#xff0c;一台配置宝塔面板&#xff0c;一台配置长亭雷池WAF 思路主要围绕&#xff1a;m…

Wpf使用NLog将日志输出到LogViewer

1 LogViewer LogViewer是通过UDP传输的高性能实时log查看器。 具有一下特性&#xff1a; 通过UDP读取日志通过文件导入日志导出日志到一个文件中排序、过滤&#xff08;日志树&#xff0c;日志等级&#xff09;和查找突出显示搜索文本从UPD接收日志时忽略IP地址列表多接收器支…

Java:Clonable 接口和拷贝

一 Clonable 接口 在 Java SE 中&#xff0c;Cloneable 是一个标记接口&#xff08;Marker Interface&#xff09;&#xff0c;它位于 java.lang 包中。这个接口的主要目的是标识实现该接口的类能够被合法地克隆&#xff08;即可以调用 Object 类中的 clone() 方法&#xff09…

【觅图网-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

神经网络面试题目

1. 批规范化(Batch Normalization)的好处都有啥&#xff1f;、 A. 让每一层的输入的范围都大致固定 B. 它将权重的归一化平均值和标准差 C. 它是一种非常有效的反向传播(BP)方法 D. 这些均不是 正确答案是&#xff1a;A 解析&#xff1a; ‌‌‌‌  batch normalization 就…

基于SpringBoot+WebSocket实现地图上绘制车辆实时运动轨迹图

实现基于北斗卫星的车辆定位和轨迹图的Maven工程&#xff08;使用模拟数据&#xff09;&#xff0c;我们将使用以下技术&#xff1a; Spring Boot&#xff1a;作为后端框架&#xff0c;用来提供数据接口。Thymeleaf&#xff1a;作为前端模板引擎&#xff0c;呈现网页。Leaflet…

算法之逻辑斯蒂回归(Logistic regression)

简介&#xff1a;个人学习分享&#xff0c;如有错误&#xff0c;欢迎批评指正。 逻辑斯蒂回归&#xff08;Logistic Regression&#xff09;是统计学中一种广泛应用于二分类问题的算法。它的主要目标是预测二分类问题中的事件发生的概率。尽管名字里有“回归”&#xff0c;但逻…

高级I/O知识分享【epoll || Reactor ET,LT模式】

博客主页&#xff1a;花果山~程序猿-CSDN博客 文章分栏&#xff1a;Linux_花果山~程序猿的博客-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我们一起努力&#xff0c;一起成长&#xff01; 目录 一&#xff0c;接口 epo…

【kaggle竞赛】毒蘑菇的二元预测题目相关信息和思路求解代码

毒蘑菇的二元预测 您提供了很多关于不同二元分类任务的资源和链接&#xff0c;看起来这些都是Kaggle竞赛中的参考资料和高分解决方案。为了帮助您更好地利用这些资源&#xff0c;这里是一些关键点的总结&#xff1a; Playground Season 4 Episode 8 主要关注的竞赛: 使用银行…

如何将很多个pdf拼接在一起?很多种PDF拼接的方法

如何将很多个pdf拼接在一起&#xff1f;将多个PDF文件合并不仅能够提升信息的整合性&#xff0c;还能使文件管理更加高效。想象一下&#xff0c;你需要向同事或老师提交一份综合报告&#xff0c;其中包含了多份相关资料。如果每个文件单独存在&#xff0c;查找和传输都会变得繁…

Java 入门指南:JVM(Java虚拟机)—— Java 类加载器详解

类加载器 类加载器&#xff08;Class Loader&#xff09;是 Java 虚拟机&#xff08;JVM&#xff09;的一部分&#xff0c;它的作用是将类的字节码文件&#xff08;.class 文件&#xff09;从磁盘或其他来源加载到 JVM 中。类加载器负责查找和加载类的字节码文件&#xff0c;并…

Python|OpenCV-实现识别目标图像中的圆圈(20)

前言 本文是该专栏的第22篇,后面将持续分享OpenCV计算机视觉的干货知识,记得关注。 在处理图像检测项目的时候,可能会遇到需要检测目标图像中的“圆圈”需求。笔者在这里举个例子,如下图所示: 在图中有一个篮球,但是我们要找的目标对象并不是篮球,而是篮球它本身的这个…

MySQL安装教程

MySQL安装教程 如果需要删除原有mysql&#xff0c;然后安装过新的&#xff0c;可以参照如何彻底卸载旧mysql重装测试 1. 准备资源 mysql官网直达&#xff1a;https://dev.mysql.com/downloads/mysql/ CADN&#xff1a;https://download.csdn.net/download/luocong321/89592962 …

《深度学习》PyTorch框架 优化器、激活函数讲解

目录 一、深度学习核心框架的选择 1、TensorFlow 1&#xff09;概念 2&#xff09;优缺点 2、PyTorch 1&#xff09;概念 2&#xff09;优缺点 3、Keras 1&#xff09;概念 2&#xff09;优缺点 4、Caffe 1&#xff09;概念 2&#xff09;优缺点 二、pytorch安装 1、安装 2、…