jvm类加载机制概述

news2024/12/23 23:24:04

18bd9cc6225d45bcb0898827946949eb.jpg、什么是jvm的类加载机制

 

  类加载机制是指我们将类的字节码文件所包含的数据读入内存,同时我们会生成数据的访问入口的一种 特殊机制。那么我们可以得知,类加载的最终产品是数据访问入口。

 

  加载类文件(即.class文件)的方式有以下几种:

 

从本地系统中直接加载。

通过网络下载的.class文件。比如Web Applet,也就是我们的小程序应用。

从war,jar等归档文件中加载class。

从专有数据库中提取.class文件。

将java源文件动态编译为.class文件,也就是运行时计算而成,java的动态代理技术就是这么实现的。

从加密文件中获取。典型的防止class文件被反编译的保护措施。

回到顶部

2、类装载的过程

  类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个过程包括:装载、验证、准备、解析、初始化、使用、卸载7个阶段。其中验证、准备、解析统称为链接。如下图     

 

 

 

 

 

装载(Loading):

通过一个类的全限定名获取定义此类的二进制字节流,由上文可知,我们不一定从字节码文件中获取字节流,还能通过上述多种方式获取字节流。

将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

在java堆中生存一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入库。 

      获取类的二进制字节流的阶段是我们java程序员最关注的阶段,也是操作性最强的一个阶段,因为这个阶段我们可以对我们的类加载器进行操作 ,比如我们想自定义类加载器进行操作完成加载,又或者我们想通过java agent来完成我们的字节码增强操作。

 

连接(Linking):

验证(Verification):验证主要是为了保证被加载类的正确性,即装载的Class文件中的字节流保护的信息是否符合当前虚拟机的要求,并且还要求我们的信息不会危害虚拟机自身的安全,导致虚拟机的崩溃。这其中包括四个阶段:

文件格式的验证:第一阶段要验证字节流是否符合class文件格式的规范,并且能被当前版本的虚拟机处理

元数据的验证:第二阶段是对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言规范的要求。

字节码验证:第三阶段是整个验证过程中最复杂的一个阶段,主要目的是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。在第二阶段对元数据信息中的数据做完校验后,这个阶段将对类对方法体进行校验分析,保证被校验类对方法在运行时不会做出危害虚拟机安全对事件。

符号引用验证:这是最后一个阶段的验证,它发生在虚拟机将符号引用转化为直接引用的时候(解析阶段), 可以看作是对类自身以外的信息(常量池中的各种符号引用)进行匹配性的校验。符号引用 验证的目的是确保解析动作能正常执行。

准备(Preparation):为类的静态变量分配内存,并将其初始化为默认值。

解析(Resolution):

初始化(Initialization):

    初始化阶段是执行类构造器()方法的过程。在准备阶段,类变量已赋过一次系统要求对初始值,而在初始化阶段,则是根据程序员通过程序制定的主观计划去初始化类变量和其他资源,比如赋值。

 

    在java中,对于初始化阶段,有且只有以下五种情况才会对要求类立刻“初始化”(加载,验证,准备,自然需要在此之前开始):

 

使用new关键字实例化对象、访问或者设置一个类的静态字段(被final修饰、编译器优化时已经放入常量池的例外)、调用类方法,都会初始化该静态字段或者静态方法所在的类。

初始化类的时候,如果其父类没有被初始化过,则要先触发其父类初始化。

使用java.lang.reflect包的方法进行反射调用的时候,如果类没有被初始化,则要先初始化。

虚拟机启动时,用户会先初始化要执行的主类(含有main)

jdk 1.7后,如果java.lang.invoke.MethodHandle的实例最后对应的解析结果是 REF_getStatic、REF_putStatic、REF_invokeStatic方法句柄,并且这个方法所在类没有初始化,则先初始化。

使用(Useing):

主动使用:

创建类的实例,也就是new的方式

访问某个类或接口的静态变量,或者对该静态变量赋值

调用类的静态方法

反射

初始化某个类的子类,则其父类也会进行初始化

java虚拟机启动时被标明为启动类的类(SpringbootApplication类)

被动使用:

引用父类的静态字段,只会引起父类的初始化,而不会引起子类的初始化

定义类数组,不会引起类的初始化      

引用类的static final常量,不会引起类的初始化(如果只有static修饰,还是会引起该类初始化 的)

 

卸载(Unloading):    

    在类使用完成之后,如果满足下面的情况,类就会被卸载:

 

该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例

加载该类的ClassLoader已经被回收

该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法 

 

  如果以上三个条件全部满足,jvm就会在方法区垃圾回收的时候对类进行卸载,类对卸载过程其实就是在方法区中清空类信息,java类对整个生命周期就结束类。但是一般情况下启动类加载器加载的类不会被卸载,而我们的其他两种基础类型的类加载器只有极少的情况下才会被卸载。

 

回到顶部

3、类的加载器

  java的类记载器是负责读取java字节码,并转换成java.lang.class类的一个实例的代码模块。类加载器除了用于加载类外,还可以用于确定类在java虚拟机的唯一性。  

 

      一个类在同一个类加载器中具有唯一性(Uniqueness),而不同类加载器中是允许同名类存在的, 这里的同名是指全限定名相同。但是在整个JVM里,纵然全限定名相同,若类加载器不同,则仍 然不算作是同一个类,无法通过 instanceOf 、equals 等方式的校验。

 

  java虚拟机自带有以下三种类加载器:

 

Bootstrap ClassLoader

负责加载$JAVA_HOME中 jre/lib/rt.jar 里所有的class或Xbootclassoath选项指定的jar包。由 C++实现,不是ClassLoader子类。

Extension ClassLoader

负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar 或 -Djava.ext.dirs 指定目录下的jar包。

Application ClassLoader  

负责加载classpath中指定的jar包及 Djava.class.path 所指定目录下的类和jar包。

 

 

  除此之外,用户也可以自定义类加载器:

 

User ClassLoad

通过java.lang.ClassLoader的子类自定义加载class,属于应用程序根据自身需要自定义的 ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader。

 

  

 

 

 

回到顶部

4、双亲委派机制

  “双亲委派”是指子类加载器如果没有加载过该目标类,就先委托父类加载器加载该目标 类,只有在父类加载器找不到字节码文件的情况下才从自己的类路径中查找并装载目标类。

 

  

 

  “双亲委派”机制加载Class的具体过程是:

 

ClassLoader先判断该Class是否已加载,如果已加载,则返回Class对象;如果没有则委托 给父类加载器。

 

父类加载器判断是否加载过该Class,如果已加载,则返回Class对象;如果没有则委托给祖 父类加载器。

 

依此类推,直到始祖类加载器(引用类加载器)。

 

始祖类加载器判断是否加载过该Class,如果已加载,则返回Class对象;如果没有则尝试从其对应的类路径下寻找class字节码文件并载入。如果载入成功,则返回Class对象;如果载入失败,则委托给始祖类加载器的子类加载器。

 

始祖类加载器的子类加载器尝试从其对应的类路径下寻找class字节码文件并载入。如果载入成功,则返回Class对象;如果载入失败,则委托给始祖类加载器的孙类加载器。

 

依此类推,直到源ClassLoader。

 

源ClassLoader尝试从其对应的类路径下寻找class字节码文件并载入。如果载入成功,则返回Class对象;如果载入失败,源ClassLoader不会再委托其子类加载器,而是抛出异常。

 

 

 

 

 

 

 

  “双亲委派”机制只是Java推荐的机制,并不是强制的机制。我们可以继承java.lang.ClassLoader类,实现自己的类加载器。如果想保持双亲委派模型,就应 该重写findClass(name)方法;如果想破坏双亲委派模型,可以重写loadClass(name)方法。

 

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

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

相关文章

一些基本类上实用的注解及例子

文章目录 一些基本类上实用的注解及例子一、Data二、Accessors三、AllArgsConstructor四、NoArgsConstructor五、EqualsAndHashCode六、后面在补充!先这样吧,哈哈!总结 一些基本类上实用的注解及例子 一、Data Data 注解是一个组合注解&…

Django源码之路由的本质(上)——逐步剖析底层执行流程

目录 1. 前言 2. 路由定义 3. 路由定义整体源码分析 3.1 partial实现path函数调用 3.2 图解_path函数 3.3 最终 4.URLPattern和Pattern的简单解析 5. 小结 1. 前言 在学习Django框架的时候,我们大多时候都只会使用如何去开发项目,对其实现流程并…

linux 软中断入门

在 linux 中,任务执行的载体有很多,包括线程,中断,软中断,tasklet,定时器等。但是从本质上来划分的话,任务执行的载体只有两个:线程和中断。软中断和 tasklet 的执行可能在中断中&am…

云服务器8核32G配置报价大全,腾讯云、阿里云和京东云

8核32G云服务器租用优惠价格表,云服务器吧yunfuwuqiba.com整理阿里云8核32G服务器、腾讯云8核32G和京东云8C32G云主机配置报价,腾讯云和京东云是轻量应用服务器,阿里云是云服务器ECS: 阿里云8核32G服务器 阿里云8核32G服务器价格…

9.动态规划——2.最大序列和

例题——最大序列和 找状态 思路一() 定义一个状态 d p [ i ] dp[i] dp[i],计为前i个数构成子序列和的最大值 此法状态转移比较困难,即若 d p [ i ] dp[i] dp[i]与 d p [ i − 1 ] dp[i-1] dp[i−1]没有明确的关系,有…

获取电商数据的几种方法分享

在数字化时代,电商数据已经成为企业决策的重要依据。无论是市场趋势的洞察、用户行为的分析,还是产品优化和营销策略的制定,都离不开电商数据的支持。本文将分享几种获取电商数据的有效方法,力求在干货满满的同时,也不…

PyCharm中出现Microsoft Defender配置建议

原因 Windows安全中心的病毒和威胁防护会自动扫描电脑中的文件夹,我们的项目文件夹和IDE文件夹也会被扫描,而PyCharm认为这会降低IDE性能。 解决方法 直接点击提示框里的自动。 或是手动给扫描添加排除项,步骤如下: 1、先打开…

Sui原生功能如何改变链上游戏体验

从zkLogin到可编程交易区块(PTB),Sui的原生功能为游戏开发人员提供了工具,最终利用了Web3的力量,给玩家带来了新的体验和参与度。之前的区块链在支持链上游戏方面存在技术上的局限,但是Sui提供了开发人员所…

受益于边缘计算的三个关键应用

边缘计算和 5G 网络正在改变物联网,增强跨多个领域的广泛应用的功能,并催生大量新兴应用。我们通过研究三个突出的用例来说明边缘计算的强大功能。 工业4.0智能工厂 工业 4.0 为制造商提供了基于灵活的工业环境提高生产力和盈利能力的愿景,…

AR-Net网络(图像篡改检测)

AR-Net网络 摘要AbstractAR-Net1. 文献摘要2. 研究背景3. 创新点4. AR-Net 网络架构5. 实验6. 结论总结 摘要 AR-Net使用自适应注意力机制来融合位置和通道维度的特征,使网络能够充分利用不同维度的被篡改特征,此外,AR-Net 改进了预测掩模&a…

牛客NC92 最长公共子序列(二)【中等 动态规划 Java,Go,PHP】

题目 题目链接: https://www.nowcoder.com/practice/6d29638c85bb4ffd80c020fe244baf11 思路 https://blog.csdn.net/qq_36544411/article/details/120021203 思路 动态规划法, 我们以dp[i][j]表示在s1中以第i个元素结尾,s2中以第j个元素结…

【JavaSE】初识线程,线程与进程的区别

文章目录 ✍线程是什么?✍线程和进程的区别✍线程的创建1.继承 Thread 类2.实现Runnable接口3.匿名内部类4.匿名内部类创建 Runnable ⼦类对象5.lambda 表达式创建 Runnable ⼦类对象 ✍线程是什么? ⼀个线程就是⼀个 “执行流”. 每个线程之间都可以按…

常见微服务的组件?

注册中心:就是一个服务注册的地方,我们可以把拆分的服务注册到注册中心,这样注册中心就能管理这些服务,服务之间的调用就会很方便,通过服务名就能相互调用。 负载均衡:被调用放的负载均衡,比如…

人工智能产业应用--具身智能

五、下一个浪潮 (一) 跳出缸中脑——虚实结合 在探索人工智能的边界时,“跳出缸中脑——虚实结合”这一概念提出了一个引人深思的视角,尤其是在具身智能的领域。具身智能是一种思想,强调智能体通过与其环境的直接物理互动来实现智能行为。然…

[MSSQL]理解SQL Server AlwaysOn AG的备份

AG提供了以下几种备份策略 下面来看看各项的解释 Prefer Secondary(首选辅助副本) 应在辅助副本上执行此可用性组的自动备份。如果没有可用的辅助副本,将在主副本上执行备份。 这个选项只是概念上的选项。基本上,用户可以从任何复制节点上执行备份命令。 我们可以在主副本…

Django DRF视图

文章目录 一、DRF类视图介绍APIViewGenericAPIView类ViewSet类ModelViewSet类重写方法 二、Request与ResponseRequestResponse 参考 一、DRF类视图介绍 在DRF框架中提供了众多的通用视图基类与扩展类,以简化视图的编写。 • View:Django默认的视图基类&…

数据结构堆

前言: 在前面我们已经学习了数据结构的基础操作:顺序表和链表及其相关内容,今天我们来学一点有些难度的知识——数据结构中的二叉树,今天我们先来学习二叉树中堆的知识,这部分内容还是非常有意思的,下面我们…

设计模式学习笔记 - 设计模式与范式 -行为型:2.观察者模式(下):实现一个异步非阻塞的EventBus框架

概述 《1.观察者模式(上)》我们学习了观察者模式的原理、实现、应用场景,重点节介绍了不同应用场景下,几种不同的实现方式,包括:同步阻塞、异步非阻塞、进程内、进程间的实现方式。 同步阻塞最经典的实现…

【 书生·浦语大模型实战营】学习笔记(一):全链路开源体系介绍

🎉AI学习星球推荐: GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系的学习资料,配有全面而有深度的专栏内容,包括不限于 前沿论文解读、…

【Linux】TCP网络套接字编程+守护进程

文章目录 日志类(完成TCP/UDP套接字常见连接过程中的日志打印)单进程版本的服务器客户端通信多进程版本和多线程版本守护进程化的多线程服务器 日志类(完成TCP/UDP套接字常见连接过程中的日志打印) 为了让我们的代码更规范化&…