JVM详解——类的加载
文章目录
- 类的加载
- 1、Java程序如何运行
- 2、Java字节码文件
- 3、类加载
- 4、类加载的过程
- 5、类加载器
- 6、类的加载方式
- 7、类的加载机制
- 8、双亲委派机制
- 9、破坏双亲委派机制
类的加载
1、Java程序如何运行
-
首先通过Javac命令将
.java
文件编译生成.class
字节码文件。
Javac是Java编译命令,编译过程分为四步。- 词法解析,通过空格分隔出单词、操作符、控制符等信息,形成信息流传递给语法解析器。
- 语法解析,将信息流按照Java语法规则组装成语法树。
- 语义分析,检查类型是否匹配、关键词是否使用合理、作用域是否正确等。
- 字节码生产,将经过1、2、3步骤生产的新型转换为字节码。
-
.class
文件加载到JVM中经过一系列类加载流程,由解释器解释执行和JIT即时编译器将字节码文件编译成本地机器码执行。字节码必须通过类加载机制加载到JVM后方能执行,执行有三种模式,解释执行、JIT编译执行、JIT编译和解释器混合执行(主流JVM默认执行的方式)。混合模式优势在于解释器在启动时先解释执行,节省编译时间。
解释执行: 来一行代码,解释一行,大部分不常用的代码,采用此种方式
即时编译: 对于部分热点代码,虚拟机将该部分字节码编译生成机器指令,以提高Java虚拟机的运行效率 -
CPU调度线程执行本地机器码
2、Java字节码文件
Class文件
本质上是一个以字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑的排列在class文件中。JVM根据其特定的规则解析该二进制数据,从而得到相关信息。Class文件
采用一种伪结构来存储数据,它有两种类型:无符号数和表。
Class文件的结构属性:
- 魔数与class文件的版本:class文件头4个字节称为魔数,是class文件的标识
- 常量池:class文件的资源仓库,存储变量的属性、类型和名称;方法的属性、类型和名称等。
- 访问标志:表示该class的属性和访问类型,比如class是类还是接口,访问类型是
public、private
,类型是否被标记为final
- 类索引、父类索引、接口索引:一种描述的数据项目,class文件凭此确定类的继承和实现关系
- 字段表属性:描述类或接口中声明的变量。比如变量的作用域(
public、private、protected
)、是否是静态变量(static
)、可变性(final
)、数据类型(基本数据类型、对象、数组)等 - 方法表属性:描述方法的类型、作用域、返回值、参数、是否是重写或重载
- 属性表属性:描述某些场景专有的信息。比如字段表中的特殊属性、方法表中的特殊属性。
3、类加载
Class 文件
中描述的各类信息都需要加载到虚拟机后才能使用。JVM 把描述类的数据从 Class 文件
加载到内存,并对数据进行加载、验证、解析和初始化
,最终形成可以被虚拟机直接使用的 数据类型,这个过程称为虚拟机的类加载过程。
与编译时需要连接的语言不同,Java 中类型的加载、连接和初始化都是在运行期间完成的,这增加了性能开销,但却提供了极高的扩展性,Java 动态扩展的语言特性就是依赖运行期动态加载和连接实现的。
4、类加载的过程
一个类从被加载到虚拟机内存开始,到卸载出内存为止,整个生命周期经历加载、验证、准备、解析、初始化、使用和卸载七个阶段,其中验证、解析和初始化三个部分称为连接。加载、验证、准备、初始化阶段开始的先后顺序是确定的,解析则不一定:可能在初始化之后再开始,这是为了支持 Java 语言的动态绑定。
-
加载:查找并加载类的二进制数据
在加载阶段,虚拟机需要完成以下三个步骤:- 通过一个类的全限定名来获取其定义的二进制字节流。
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在Java堆内存中生成一个代表这个类的
java.lang.Class
对象,作为对方法区中这些数据的访问入口。
-
验证: 确保被加载类的正确性
确保Class文件
的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证分为4个阶段:文件格式验证、元数据验证、字节码验证、符号引用验证。
验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用
-Xverifynone参数
来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。
-
准备:为类的静态变量分配内存,并将其初始化为默认值
准备阶段是正式为类变量分配内存并设置类变量初始值零值的阶段,这些内存都将在方法区中分配。
注: 此时分配的是类变量(static
),不包括实例变量。初始化的值是数据类型的默认零值,比如0、0L、null、false
等。 -
解析:把类中的符号引用转换为直接引用
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。符号引用就是一组符号来描述目标,可以是任何字面量。
直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄
- 初始化:JVM对类进行初始化赋值
为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。
在Java中对类变量进行初始值设定有两种方式:
- 声明类变量是指定初始值
- 使用静态代码块为类变量指定初始值
JVM初始化步骤:
- 假如这个类还没有被加载和连接,则程序先加载并连接该类
- 假如该类的直接父类还没有被初始化,则先初始化其直接父类
- 假如类中有初始化语句,则系统依次执行这些初始化语句
- 使用:使用类的对象实例
类访问方法区内的数据结构的接口, 对象是堆区的数据。 - 卸载:类被卸载出内存
Java虚拟机结束,类被卸载出内存。
Java虚拟机结束生命周期的情况:- 执行了System.exit()方法
- 程序正常执行结束
- 程序在执行过程中遇到了异常或错误而异常终止
- 由于操作系统出现错误而导致Java虚拟机进程终止
5、类加载器
启动类加载器:
Bootstrap ClassLoader
,负责加载存放在JDK的安装目录下的jre\lib
中,或被-Xbootclasspath参数
指定的路径中的,并且能被虚拟机识别的类库(如rt.jar
,所有的java.*
开头的类均被Bootstrap ClassLoader
加载)。启动类加载器是无法被Java程序直接引用的。
扩展类加载器:
Extension ClassLoader
,该加载器由sun.misc.Launcher$ExtClassLoader
实现,它负责加载JDK安装目录下的jre\lib\ext
目录中,或者由java.ext.dirs
系统变量指定的路径中的所有类库(如javax.*
开头的类),开发者可以直接使用扩展类加载器。
应用程序类加载器:
Application ClassLoader
,该类加载器由sun.misc.Launcher$AppClassLoader
来实现,它负责加载用户类路径(ClassPath)
所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
6、类的加载方式
类加载有三种方式:
1、命令行启动应用时候由JVM初始化加载
2、通过Class.forName()
方法动态加载
3、通过ClassLoader.loadClass()
方法动态加载
Class.forName()和ClassLoader.loadClass()区别?
Class.forName():
将类的.class文件加载到JVM中,还会对类进行解释,执行类中的static块
;ClassLoader.loadClass():
只会将.class文件
加载到JVM中,不会执行static
中的内容,只有在newInstance()
方法创建类对象时才会去执行static块
。Class.forName(name, initialize, loader)
带参函数也可控制是否加载static
块。并且只有调用了newInstance()
方法构造函数创建类的对象时才会加载static块
。
7、类的加载机制
- 缓存机制,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。(修改了class后,需要重启虚拟机,程序的修改才会生效)
- 双亲委派机制, 如果一个类加载器收到了类加载的请求,首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上。因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,也就是无法完成该加载,子加载器才会尝试自己去加载该类。
8、双亲委派机制
-
当
AppClassLoader
加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader
去完成。 -
当
ExtClassLoader
加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader
去完成。 -
如果
BootStrapClassLoader
加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class),会使用ExtClassLoader来尝试加载; -
若
ExtClassLoader
也加载失败,则会使用AppClassLoader
来加载,如果AppClassLoader
也加载失败,则会报出异常ClassNotFoundException
。
双亲委派机制的好处:
- 系统类防止内存中出现多份同样的字节码(比如自己写的
String类
与JDK中的String类
会优先使用JDK中的系统API) - 保证Java程序安全稳定运行
- 解决了各个类加载器的基础类统一问题
9、破坏双亲委派机制
为什么要破坏双亲委派?
举个🌰: 我们常用数据库驱动Driver
接口,Driver
定义在JDK
中,但其实现是各个数据库服务商,比如:MySQL
的MYSQL CONNECROR
,因此DriverManger
要加载各个Driver
接口实现类进行管理,但是DriverManager
是由启动类加载器进行加载的,而这个启动类加载器默认值加载JDK安装目录下面的lib文件下的类库,但我们真正要加载的是各个实现类,需要有应用程序类加载器进行加载,这个时候就需要启动类加载器委托应用程序类加载器去加载Driver
实现类,从而破坏了双亲委派。
破坏方式:
- 自定义类加载,重写
loadclass
方法。双亲委派的机制都是通过这个方法实现的,这个方法可以指定类通过什么类加载器来进行加载,所以如果改写他的加载规则,相当于打破双亲委派机制。 - 线程上下文类加载器: 提供父类加载器访问子类加载器的行为。
双亲委派很好的解决了各个类加载器的基础类统一问题,基础类总是被用户代码所调用,但是如果基础类又要重新调用用户代码,此时就与双亲委派模型的设计理念相违背。
比如:JNDI服务(JDBC/JCE/JAXB/JBI)
是Java的标准服务,它的代码是由启动类加载器进行加载的,但是JNDI的作用就是进行资源的集中管理和查找,它需要调用由(服务厂商提供的实现类)开发人员在classpath
下的类代码,但是启动类加载器不会进行加载。
所以引入线程上下类加载器,通过java.lang.Thread
类的setContextClassLoader()
方法进行设置。如果创建线程时还未设置,它会从父线程继承一个,如果在应用程序全局范围内没有设置,那么这个线程上下类加载器就是应用程序类加载器。 - Java热部署
Java热部署的规范化模块是OSGi提供的,热部署实现的关键就是OSGi自定义了类加载器,它为每个模块都配了一个类加载器。当需要动态地更换一个模块的时候,就把模块连通这个模块的类加载器一起替换,从而实现了热替换。此时类加载器从树状结构变为了网状结构,有大量的层与层之间的类加载器,所以就打破了双亲委派模型。
参考文章:
- https://pdai.tech/md/java/jvm/java-jvm-classload.html
- https://blog.csdn.net/Wangxichuan_Jack/article/details/123711799
- https://blog.csdn.net/Fqzzzzz/article/details/123989751
- https://blog.csdn.net/weixin_45629285/article/details/128050932
相关文章:
JVM详解——类的加载
文章目录类的加载1、Java程序如何运行2、Java字节码文件3、类加载4、类加载的过程5、类加载器6、类的加载方式7、类的加载机制8、双亲委派机制9、破坏双亲委派机制类的加载 1、Java程序如何运行 首先通过Javac命令将.java文件编译生成.class字节码文件。 Javac是Java编译命令&a…...
Ubuntu最新版本(Ubuntu22.04LTS)安装nfs服务器及使用教程
目录 一、概述 二、在Ubuntu搭建nfs服务器 👉2.1 安装nfs服务器 👉2.2 创建nfs服务器共享目录 👉2.3 修改nfs服务器配置文件 👉2.4 重启nfs服务器 三、客户端访问nfs服务器共享目录 🎈3.1 在nfs客户端挂载服…...
Python-第九天 Python异常、模块与包
Python-第九天 Python异常、模块与包一、了解异常1. 什么是异常:2. bug是什么意思:二、异常的捕获方法1. 为什么要捕获异常?2. 捕获异常的语法3. 如何捕获所有异常?三、异常的传递性1.异常是具有传递性的四、Python模块1. 什么是模…...
博彩公司 BetMGM 发生数据泄露,“赌徒”面临网络风险
Bleeping Computer 网站披露,著名体育博彩公司 BetMGM 发生一起数据泄露事件,一名威胁攻击者成功窃取其大量用户个人信息。 据悉,BetMGM 数据泄漏事件中,攻击者盗取了包括用户姓名、联系信息(如邮政地址、电子邮件地址…...
初探Mysql反向读取文件
前言 Mysql反向读取文件感觉蛮有意思的,进行了解过后,简单总结如下,希望能对在学习Mysql反向读取文件的师傅有些许帮助。 前置知识 在Mysql中存在这样一条语句 LOAD DATA INFILE它的作用是读取某个文件中的内容并放置到要求的表中&#x…...
地图坐标系大全:常用地图坐标系详解与转换指南
介绍地图坐标系的基本概念和原理地图坐标系是用于描述地图上位置的数学模型。它可以用来表示地球表面上的任意一个点,使得这个点的位置可以在地图上精确定位。不同的地图坐标系采用不同的基准面和投影方式,因此会有不同的坐标系参数,不同的坐…...
使用 URLSearchParams 解析和管理URL query参数
介绍 首先 URLSearchParams是一个构造函数,会生成一个URLSearchParams对象,参数类型: 不传 | string | object | URLSearchParams, 并且遇到特殊字符它会自动帮我们encode 和 decode const ur…...
一台电脑安装26个操作系统(windows,macos,linux,chromeOS,Android,静待HarmonyOS)
首先看看安装了哪些操作系统1-4: windows系统 四个5.Ubuntu6.deepin7.UOS家庭版8.fydeOS9.macOS10.银河麒麟11.红旗OS12.openSUSE Leap13.openAnolis14.openEuler(未安装桌面UI)15.中标麒麟(NeoKylin)16.centos17.debian Edu18.fedora19.oraclelinux(特别…...
Python配置文件管理之ini和yaml文件读取
1. 引言 当我们设计软件时,我们通常会花费大量精力来编写高质量的代码。但这往往还不够,一个好的软件还应该考虑其整个系统,如测试、部署、网络等。其中最重要的一个方面是配置管理。 良好的配置管理应允许在任何环境中执行软件而不更改代码…...
实战一(下):如何利用基于充血模型的DDD开发一个虚拟钱包系统?
上一节课,我们做了一些理论知识的铺垫性讲解,讲到了两种开发模式,基于贫血模型的传统开发模式,以及基于充血模型的DDD开发模式。今天,我们正式进入实战环节,看如何分别用这两种开发模式,设计实现一个钱包系统。话不多说,让我们正式…...
webpack当中的代码分割详解
A.代码分割方法一:将原来的单入口文件改为多入口文件 将不同的文件例如js代码文件分为入口文件和测试文件,这个时候打包出来的代码就会根据不同的文件单独打包成属于他们自己的文件 例如以下为单入口文件: entry: ./src/js/index.js 多入口文件:(在输出…...
【SSM】Spring对IoC的实现方式DI详讲
控制反转的一种实现方式——依赖注入一、IoC 控制反转(Overview)依赖注入(DI)- Overview利用 IoC(控制反转)这种思想有什么好处呢?二、依赖注入的方式setter 方式(xml配置中的proper…...
【QT 5 相关实验-示波器-学习笔记-示波器组件练习与使用总结】
【QT 5 相关实验-示波器-学习笔记-示波器组件练习与使用总结】1、概述2、实验环境3、参考资料-致谢4、自我提升实验效果视频演示5、代码练习-学习后拆解-实验步骤(1)头文件部分-"mwaveview.h"(2)cpp文件部分-"mwav…...
二维数组中的查找(两种解法,各有千秋)
凡事都有可能,永远别说永远。——《放牛班的春天》今天一题为再一个行列都有序的二维数组中寻找一个目标值,我们第一时间想到的可能是很暴力的解法,例如从头到尾进行遍历,这样能做出来,但是借用武忠祥老师的一句话&…...
quartz使用及原理解析
quartz简介 Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer。但是相较于Timer, Quartz增加了很多功能: 持久性作业 - 就是保持调度…...
Datawhale组队学习:大数据 D2——分布式文件系统(HDFS)
妙趣横生大数据 Day2三、Hadoop 分布式文件系统(HDFS)1. 分布式文件系统2. HDFS 简介3. HDFS 体系结构4. HDFS存储原理数据冗余存储数据存储策略数据错误与恢复5. HDFS数据读写过程读写过程HDFS故障类型和其检测方法HDFS编程实验1. 本地和集群文件间操作2. 基本文件操作3. Hado…...
CCIE重认证-300-401-拖图题全
拖图 拖图题 编程 snippet;192.168.5.0,mask 255.255.255.0;number是192.168.5.0;mask是255.255.255.0 snippets;edit-config对config,loopback对name 100,address对primary,mask…...
如何动态的创建类?type的其他用法?什么是元类,如何自定义元类?
1、python中一切都是对象,类也不例外,type是object的子类,是创建类的类。 如何动态的创建一个类? 用脚丫子创建 用脑子创建 不会 不知道什么事动态类 大家可能会有一堆的疑惑,是的我也是有很多疑惑那让我们一起来探个…...
XCP实战系列介绍15-XCP故障排查指导
本文框架 1.概述2. 通过调试器排查2.1 打开Det功能2.2 如何确定Det ErrorCode3. 通过XCP应答报文排查3.1 FE报文组成及故障码对应关系3.2 举个例子1.概述 前面几篇文章我们介绍了基于Davinci开发工具的XCP配置指导,配好了,代码也生成了,但是程序一定能正常跑起来吗?就算软…...
吉林大学软件需求分析与规范(Software Requirements Analysis Specification)
chapter0课程简介:◼ 软件工程专业核心课程之一◼ 软件工程课程体系最前端课程◼ 主要内容:需求的基本概念,需求的分类,需求工程的基本过程,需求获取的方法、步骤、技巧,需求分析和建模技术,需求…...
PyTorch - Conv2d 和 MaxPool2d
文章目录Conv2d计算Conv2d 函数解析代码示例MaxPool2d计算函数说明卷积过程动画Transposed convolution animationsTransposed convolution animations参考视频:土堆说 卷积计算 https://www.bilibili.com/video/BV1hE411t7RN 关于 torch.nn 和 torch.nn.function t…...
leetcode Day2(昨天实习有点bug,心态要崩了)
int carry 0;for(int i a.size() - 1, j b.size() - 1; i > 0 || j > 0 || carry; --i, --j) {int x i < 0 ? 0 : a[i] - 0;int y j < 0 ? 0 : b[j] - 0;int sum (x y carry) % 2;carry (x y carry) / 2;str.insert(0, 1, sum 0);}return str;加一&a…...
另一种思考:为什么不选JPA、MyBatis,而选择JDBCTemplate
以下内容转载自:https://segmentfault.com/a/1190000018472572 作者:scherman 因为项目需要选择数据持久化框架,看了一下主要几个流行的和不流行的框架,对于复杂业务系统,最终的结论是,JOOQ是总体上最好的…...
LeetCode 338. 比特位计数
给你一个整数 n ,对于 0 < i < n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n 1 的数组 ans 作为答案。 示例 1: 输入:n 2 输出:[0,1,1] 解释: 0 --> 0 1 --> …...
排序评估指标——NDCG和MAP
在搜索和推荐任务中,系统常返回一个item列表。如何衡量这个返回的列表是否优秀呢? 例如,当我们检索【推荐排序】,网页返回了与推荐排序相关的链接列表。列表可能会是[A,B,C,G,D,E,F],也可能是[C,F,A,E,D],现在问题来了…...
[Android Studio] Android Studio Virtual Device(AVD)虚拟机的功能试用
🟧🟨🟩🟦🟪 Android Debug🟧🟨🟩🟦🟪 Topic 发布安卓学习过程中遇到问题解决过程,希望我的解决方案可以对小伙伴们有帮助。 🚀write…...
kafka-3-kafka应用的核心要点和内外网访问
kafka实战教程(python操作kafka),kafka配置文件详解 Kafka内外网访问的设置 1 kafka简介 根据官网的介绍,ApacheKafka是一个分布式流媒体平台,它主要有3种功能: (1)发布和订阅消息流,这个功能类似于消息队列&#x…...
VS2017+OpenCV4.5.5 决策树-评估是否发放贷款
决策树是一种非参数的监督学习方法,主要用于分类和回归。 决策树结构 决策树在逻辑上以树的形式存在,包含根节点、内部结点和叶节点。 根节点:包含数据集中的所有数据的集合内部节点:每个内部节点为一个判断条件,并且…...
Prometheus 记录规则和警报规则
前提环境: Docker环境 涉及参考文档: Prometheus 录制规则Prometheus 警报规则 语法检查规则 promtool check rules /path/to/example.rules.yml一:录制规则语法 groups 语法: groups:[ - <rule_group> ]rule_group…...
(API)接口测试的关键技术
接口测试也就是API测试,从名字上可以知道是面向接口的测试活动。所以在讲API测试之前,我们应该说清楚接口是什么,那么接口就是有特定输入和特定输出的一套逻辑处理单元,而对于接口调用方来说,不用知道自身的内部实现逻…...
做cpa用什么网站/网站百度权重
在使用Ueditor时,如要简化工具栏上的按钮,可以修改配置项的方法: 1. 方法一:修改 ueditor.config.js 里面的 toolbars 2. 方法二:实例化编辑器的时候传入 toolbars 参数 我一般用第二种方法, <script sr…...
网站建设的素材/seo网站关键词排名优化公司
我思考了一下上一个程序为什么会失败,可能还是太远了,所以这次弄近一点。把5000米改成1000米吧。。。其他的还是不变 function的持续不变,在这里就不重复写了,具体参照上一篇博客 主函数:关于亮点1 % clc;close all;cl…...
中国疫情即将放开/外贸网站seo推广教程
遇到的几个问题: 1、android-ndk-r8d/build/core/build-binary.mk:41:***target file clean has both : and :: entries. Stop 解决办法:因为在libavfilter目录中的Makefile的末尾处多了Clean这个玩意儿将其注释掉或者删掉就可以了 2、parseutils.c文件多…...
外网访问wordpress版式不对/百度关键词下拉有什么软件
链表 在内存空间中,数组和链表都是基本的数据结构,都是【表】,或者叫【线性表】。线性表是一个线性结构,它是一个含有n≥0个结点的有限序列,对于其中的结点,有且仅有一个开始结点没有前驱但有一个后继结点…...
17网站一起做网店官网/我想创建一个网络平台
array_unique() //移除重复数据array_unshift(); //在数组的头部追加数组元素array_shift() //在数组的尾部追加数组元素if(!is_null(array_shift($array1))) //删除成功array_pop() //删除最后一个元素,移除失败返回NULLarray_push() //在数组尾部追加元素arra…...
网站里面的视频功能怎么做/产品营销策略有哪些
作者在开始讲正文之前先对读者做了一个小测验:换一个灯泡需要多少个程序员?(貌似换灯泡跟程序员关系不大),可能有三种答案: 1.根本不需要,因为灯泡根本没坏。 2.仅仅需要一名,但是需要耗费一整…...