当前位置: 首页 > news >正文

JVM:虚拟机类加载机制

JVM:虚拟机类加载机制

在这里插入图片描述

什么是JVM的类加载

众所周知,Java是面向对象编程的一门语言,每一个对象都是一个类的实例。所谓类加载,就是JVM虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。 动态的类型加载也是Java语言的一个重要特性之一,比如Android中的Retrofit库的动态代理在一定程度上也依赖于动态的类型加载。

类加载的生命周期

关于类加载的生命周期实际上在之前的一篇文章中已经粗略地提到过了:
在这里插入图片描述
这里我们以《深入理解JVM虚拟机》为准,完整地描述出其七个生命周期:
在这里插入图片描述

类的加载过程

Java虚拟机中类加载的全过程包括:加载,验证,准备,解析和初始化这五个过程,接下来我们分别来看这五个步骤:

1.加载

在加载阶段,JVM主要需要完成以下三件事情:

  • 通过一个类的全限定名来获取定义此类的二进制字节码
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  • 内存中生成代表该类的java.lang.Class文件,作为方法区这个类的各种数据的访问入口

其中,获取定义此类的二进制字节码这个行为默认情况下就是从.class的字节码文件中读取,不过我们也可以通过自定义的类加载器从诸如 网络,数据库等中读取字节码流,从而达到动态加载的目的。

而对于数组来说则是由JVM直接在内存中动态构造出来的,不过数组的元素类型最终还是要依靠类加载器来完成加载。

加载阶段结束后,JVM的方法区之中就存在对应类的相关数据了,当这些数据都被安放完成之后,会在Java堆内存中实例化一个java.lang.Class类的对象,该对象就是程序访问方法区中数据的外部接口。

2.验证

所谓验证阶段,就是JVM确保Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束,确保这些信息被当做代码运行后不会危害JVM自身的安全。

从整体上来看,验证阶段大致可以分为四个阶段的校验动作:文件格式验证,元数据验证,字节码验证,符号引用验证。

文件格式验证

验证过程的第一个阶段就是验证文件的格式是否合法,并且能否被当前版本的JVM所处理。这一阶段的验证点主要有:

  • 是否以魔数0xCAFEBABE开头
  • 主,次版本号是否在当前JVM所接受范围之内

总之,该阶段的主要目的是保证输入的字节流能被正确地解析并存储进方法区之中,并且格式上符合一个Java类型信息的要求。只有通过了该阶段的验证之后,字节流才能被存储进方法区之中,所以后面三个阶段都是基于方法区的存储结构上进行的,不会再直接操作字节流了。

元数据验证

第二阶段主要是对字节码描述的信息做语义上的分析,以确保其符合《Java语言规范》的要求。拿什么是语义上的分析呢?验证点就包括有:

  • 这个类是否有父类(除了Object之外,其余所有类都应当有父类)
  • 这个类的父类是否继承了不允许被继承的类(即被final修饰)
  • 如果这个类不是抽象类,是否实现了其父类或接口中要求实现的所有方法

可以看到,该阶段的验证条件实际上就是我们在学习Java语法中的一些规定;总之第二阶段的主要目的是对类的元数据信息进行语义校验,保证不存在与《Java语言规范》定义相悖的元数据信息。

字节码验证

第三个阶段是整个验证阶段最复杂的过程,主要目的是通过数据流分析和控制流分析,确定程序语义是合法且符合逻辑的,保证被校验类的方法在运行时不会做出危害虚拟机的行为。

符号引用验证

最后一个阶段发生在虚拟机将符号引用转化为直接引用的时候,而这个动作是在解析阶段中发生的。符号引用验证可以看做是对类自身以外(常量池中的各种符号引用)的各类信息进行匹配性校验,通俗来讲就是该类是否缺少或者被禁止访问它依赖的某些外部类,方法,字段等资源。

3.准备

准备阶段是正式为类中定义的变量(即静态变量)分配内存并设置初值的过程,在JDK7之前类变量将被存储在方法区之中,而在JDK7后类变量则会随着Class对象一起存放在Java堆中。这里的初始化指的又是数据类型的置零,比如说:

public static int value = 123;

那变量在准备阶段过后是0而不是123,因为此时尚未执行任何Java方法,而赋值语句是存放在类构造器<clinit>之中的,这个赋值动作要到类的初始化阶段才会执行。

不过这个置零也有例外情况,如果该字段是常量的话,也就是:

public static final int value = 123;

这种情况下value的值就将直接被赋值为123。

4.解析

解析阶段是JVM将常量池内的符号引用替换为直接引用的过程,这个过程的逻辑比较复杂,简单来说就是将符号替换成直接指向对应变量的地址,此处我们就不展开了。

5.初始化

初始化阶段是类加载过程的最后一个步骤,之前的准备阶段中我们已经将变量赋值成零值了(除了常量),而在初始化阶段则会根据我们编写的程序进行相应变量的初始化。具体来说,初始化阶段就是执行类构造器<clinit>()方法的过程,至于这个<clinit>()方法并不是程序员直接编写的,该方法是由编译器自动收集所有类变量的赋值动作和静态语句块中的语句合并而成的。

类加载器

之前在类的加载过程中我们提到了一个类并不仅仅可以通过class文件读取,它还可以通过其他各种手段来将类加载进方法区中,其中类加载器就是用来进行类加载的工具。

类与类加载器

顾名思义,每一个类都是由类加载器加载进入JVM之中的,虽然类加载器只用来实现类的加载动作,但是其作用远超其加载阶段。

对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在JVM中的唯一性。 也就是说,只有当字节码相同且由同一个类加载器加载时才能认为这两个类是相同的,每一个类加载器都有其自己的类名称空间。

双亲委派模型

所谓双亲委派是Java默认情况下的类加载机制遵守的原则。站在JVM的视角上只有启动类加载器和其他类加载器这两种类加载器。启动类加载器属于JVM的一部分,它是由C++语言实现的;而其他的类加载器则是由Java语言实现的,不属于JVM的一部分且全部继承于抽象类java.lang.ClassLoader

而双亲委派则是涉及到三层类加载器:

  • 启动类加载器:这个加载器是负责加载存放在<JAVA_HOME>\lib目录并且可以被JVM识别的类库;
  • 拓展类加载器:它是负责加载<JAVA_HOME>\lib\ext目录下的类库
  • 应用程序类加载器:这个类是用来加载用户类路径上的所有类库,我们同样可以直接使用这个加载器,一般情况下这就是程序中默认的类加载器

这三层类加载器在双亲委派模型下的关系如下所示:
在这里插入图片描述
除了启动类加载器之外,其他所有的类加载器都应该有自己的父加载器,不过他们之间并不是通过继承来实现的,非要说的话可能更接近于责任链模式

双亲委派模式的具体原则是: 如果一个类加载器受到了类加载的请求,它首先不会自己尝试加载,而是把这个请求委派给父加载器去实现,每一个层次的类加载器的行为都是如此,所以说所有的类加载请求首先都会被发送到启动类加载器去进行加载。只有当父加载器无法实现类的加载时子加载器才会尝试进行类的加载。

使用双亲委派模型的好处也是显而易见的:
首先它保证了JVM中的一些系统类不会被轻易地被替换,因为大部分的系统类,比如说Object类都是在系统类启动器管理的目录下的;其次,这种层次关系保证了同一个类(class)文件加载后的类都是相同的(由同一个类加载器加载的)

相关文章:

JVM:虚拟机类加载机制

JVM:虚拟机类加载机制 什么是JVM的类加载 众所周知&#xff0c;Java是面向对象编程的一门语言&#xff0c;每一个对象都是一个类的实例。所谓类加载&#xff0c;就是JVM虚拟机把描述类的数据从class文件加载到内存&#xff0c;并对数据进行校验&#xff0c;转换解析和初始化&a…...

PHP筆記

​ 前言因緣際會下還是開始學習php了。經歷了風風雨雨終於在今年暑假要去加拿大留學了&#xff0c;php會是第二年的其中一門必修課程&#xff0c;加上最近前端也真的蠻心累&#xff0c;也許有一門精進的後端語言&#xff0c;日後轉職會有更寬廣的道路&#xff0c;對自己說加油&…...

IDEA启动报错Failed to create JVM. JVM path的解决办法

今天启动IDEA时IDEA报错&#xff0c;提示如下。 if you already hava a JDK installed, define a JAVA_HOME variable in Computer > Systen Properties > System Settings > Environment Variables.Failed to create JVM. JVM path:D:\ideaIU2023.2.3\IntelliJ IDE…...

源码解析FlinkKafkaConsumer支持周期性水位线发送

背景 当flink消费kafka的消息时&#xff0c;我们经常会用到FlinkKafkaConsumer进行水位线的发送&#xff0c;本文就从源码看下FlinkKafkaConsumer.assignTimestampsAndWatermarks指定周期性水位线发送的流程 FlinkKafkaConsumer水位线发送 1.首先从Fetcher类开始&#xff0c…...

Nginx:动静分离(示意图+配置讲解)

示意图&#xff1a; 动静分离 动静分离是指将动态内容和静态内容分开处理的一种方式。通常&#xff0c;动态内容是指由服务器端处理的&#xff0c;例如动态生成的网页、数据库查询等。静态内容是指不需要经过服务器端处理的&#xff0c;例如图片、CSS、JavaScript文件等。通过…...

通讯网关软件024——利用CommGate X2Access实现Modbus TCP数据转储Access

本文介绍利用CommGate X2ACCESS实现从Modbus TCP设备读取数据并转储至ACCESS数据库。CommGate X2ACCESS是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;实现从Modbus TCP设备读取数据并转储…...

vim工具的使用

目录 vi/vim键盘图 1、vim的基本概念 2、vim的基本使用 3、vim命令模式命令集 4、vim底行模式命令集 5、参考资料 vi/vim键盘图 1、vim的基本概念 vi和vim的区别&#xff1a;vi和vim的区别简单点来说&#xff0c;它们都是多模式编辑器&#xff0c;不同的是vim是vi…...

Docker学习_存储篇

当以默认的方式创建容器时&#xff0c;容器中的数据无法直接和其他容器或宿主机共享。为了解决这个问题需要学习一些Docker 存储卷的知识。 Docker提供了三种存储的方式。 bind mount共享宿主机文件目录volume共享docker存储卷tmpfs mount共享内存 volume* volume方式是容器…...

微信小程序获取当前日期时间

一、直接使用方式 在小程序中获取当前系统日期和时间&#xff0c;可直接拿来使用的常用的日期格式 //1. 当前日期 YYYY-MM-DDnew Date().toISOString().substring(0, 10)new Date().toJSON().substring(0, 10)//2. 当前日期 YYYY/MM/DDnew Date().toLocaleDateString()//3.…...

Unity关键词语音识别

一、背景 最近使用unity开发语音交互内容的时候&#xff0c;遇到了这样的需求&#xff0c;就是需要使用语音关键字来唤醒应用程序&#xff0c;然后再和程序做交互&#xff0c;有点像智能音箱的意思。具体的技术方案方面&#xff0c;也找了一些第三方的服务&#xff0c;比如百度…...

SpringBoot的配置文件——.yml和.properties

目录 1. Spring Boot 配置文件的使用场景 2. 配置文件的两种格式 2.0 特殊说明&#xff1a; 2.1 .properties 2.1.1 格式 2.2.2 缺陷 2.2.3 解决中文乱码的问题 2.2 .yml 2.2.3 格式 配置数据库连接 注意转义字符 ​编辑 ​编辑 配置null 配置对象 从.yml读取文件举例 Stud…...

Retrieve Anything To Augment Large Language Models

简介 论文主要介绍了一套通过对比学习和蒸馏学习的方法&#xff0c;来增强学习了embedding向量&#xff0c;然后能够在知识增强&#xff0c;长上下文建模&#xff0c;ICL和工具学习等方面来增强大模型能力。...

什么是面向对象编程

面向对象编程&#xff08;Object-oriented programming&#xff0c;简称OOP&#xff09;是一种编程范型&#xff0c;通过将数据和方法&#xff08;即属性和行为&#xff09;组织在一个单元中&#xff0c;以模拟现实世界中的实体或概念。在面向对象编程中&#xff0c;数据和方法…...

c++视觉处理----固定阈值操作:Threshold()函数,实时处理:二值化,反二值化,截断,设为零,反向设为零

固定阈值操作&#xff1a; Threshold()函数 cv::threshold() 函数是OpenCV中用于执行固定阈值二值化操作的函数。它可以用来将图像中的像素值根据用户定义的阈值转换为二进制值&#xff08;0或255&#xff09;&#xff0c;以便进行图像分割、物体检测和特征提取等任务。 cv::…...

KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(8)

接前一篇文章:KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(7) 上一回讲到了drm_internal_framebuffer_create函数中的framebuffer_check函数中的drm_get_format_info函数,讲解了该函数的第一部分暨前一部分,本文讲解后一部分。为了便于理解以及理清脉络和当前所…...

【问题解决】Ubuntu 安装 SeisSol 依赖 easi 报错解决: undefined reference to `H5free_memory‘

兼职帮客户安装 SeisSol 时问题解决&#xff0c;安装 easi 这个报错卡了很久&#xff08;搞了一天&#xff09;&#xff0c;记录下&#xff0c;以备后用~ # 编译器问题 rootubuntu:/opt/easi# make -j install [ 4%] Building CXX object CMakeFiles/easi.dir/src/component/…...

循环小数(Repeating Decimals, ACM/ICPC World Finals 1990, UVa202)rust解法

输入整数a和b&#xff08;0≤a≤3000&#xff0c;1≤b≤3000&#xff09;&#xff0c;输出a/b的循环小数表示以及循环节长度。例如a5&#xff0c;b43&#xff0c;小数表示为0.(116279069767441860465)&#xff0c;循环节长度为21。 解法 就是模拟竖式除法 use std::{collecti…...

[GAMES101]透视投影变换矩阵中为什么需要改变z值

一、问题提出 在GAMES101-Lecture4 Transformation Matrices 一节中&#xff0c;闫老师介绍了正交投影和透视投影。 在讲透视投影变换矩阵 M p e r s p → o r t h o M_{persp→ortho} Mpersp→ortho​时&#xff0c;同学们对矩阵中的z分量是变化的还是不变的有很多争论。即下…...

sklearn处理离散变量的问题——以决策树为例

最近做项目遇到的数据集中&#xff0c;有许多高维类别特征。catboost是可以直接指定categorical_columns的【直接进行ordered TS编码】&#xff0c;但是XGboost和随机森林甚至决策树都没有这个接口。但是在学习决策树的时候&#xff08;无论是ID3、C4.5还是CART&#xff09;&am…...

QT 数据库表格----QSqlTableModel

将数据库数据以表格的形式转化处理的方法很多&#xff0c;但我觉得QSqlTableModel这个model应算是非常好用的&#xff1b; msql.exec("create table alldata(照片,车牌号 "",入车时间,出车时间,金额,状态,看守人员);"); //创建表格 //msql 打开的数据库即Q…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...

uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略&#xff08;地理位置/文件&#xff09; 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型&#xff0c;核心实现方式&#xff1a; 标准消息类型&#xff1a;直接使用 SDK 内置类型&#xff08;文件、图片等&#xff09;自…...

算法打卡第18天

从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…...

jdbc查询mysql数据库时,出现id顺序错误的情况

我在repository中的查询语句如下所示&#xff0c;即传入一个List<intager>的数据&#xff0c;返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致&#xff0c;会导致返回的id是从小到大排列的&#xff0c;但我不希望这样。 Query("SELECT NEW com…...