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的类加载 众所周知,Java是面向对象编程的一门语言,每一个对象都是一个类的实例。所谓类加载,就是JVM虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化&a…...
PHP筆記
前言因緣際會下還是開始學習php了。經歷了風風雨雨終於在今年暑假要去加拿大留學了,php會是第二年的其中一門必修課程,加上最近前端也真的蠻心累,也許有一門精進的後端語言,日後轉職會有更寬廣的道路,對自己說加油&…...

IDEA启动报错Failed to create JVM. JVM path的解决办法
今天启动IDEA时IDEA报错,提示如下。 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的消息时,我们经常会用到FlinkKafkaConsumer进行水位线的发送,本文就从源码看下FlinkKafkaConsumer.assignTimestampsAndWatermarks指定周期性水位线发送的流程 FlinkKafkaConsumer水位线发送 1.首先从Fetcher类开始,…...

Nginx:动静分离(示意图+配置讲解)
示意图: 动静分离 动静分离是指将动态内容和静态内容分开处理的一种方式。通常,动态内容是指由服务器端处理的,例如动态生成的网页、数据库查询等。静态内容是指不需要经过服务器端处理的,例如图片、CSS、JavaScript文件等。通过…...

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

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

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

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

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

SpringBoot的配置文件——.yml和.properties
目录 1. Spring Boot 配置文件的使用场景 2. 配置文件的两种格式 2.0 特殊说明: 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
简介 论文主要介绍了一套通过对比学习和蒸馏学习的方法,来增强学习了embedding向量,然后能够在知识增强,长上下文建模,ICL和工具学习等方面来增强大模型能力。...
什么是面向对象编程
面向对象编程(Object-oriented programming,简称OOP)是一种编程范型,通过将数据和方法(即属性和行为)组织在一个单元中,以模拟现实世界中的实体或概念。在面向对象编程中,数据和方法…...

c++视觉处理----固定阈值操作:Threshold()函数,实时处理:二值化,反二值化,截断,设为零,反向设为零
固定阈值操作: Threshold()函数 cv::threshold() 函数是OpenCV中用于执行固定阈值二值化操作的函数。它可以用来将图像中的像素值根据用户定义的阈值转换为二进制值(0或255),以便进行图像分割、物体检测和特征提取等任务。 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 时问题解决,安装 easi 这个报错卡了很久(搞了一天),记录下,以备后用~ # 编译器问题 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(0≤a≤3000,1≤b≤3000),输出a/b的循环小数表示以及循环节长度。例如a5,b43,小数表示为0.(116279069767441860465),循环节长度为21。 解法 就是模拟竖式除法 use std::{collecti…...

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

sklearn处理离散变量的问题——以决策树为例
最近做项目遇到的数据集中,有许多高维类别特征。catboost是可以直接指定categorical_columns的【直接进行ordered TS编码】,但是XGboost和随机森林甚至决策树都没有这个接口。但是在学习决策树的时候(无论是ID3、C4.5还是CART)&am…...
QT 数据库表格----QSqlTableModel
将数据库数据以表格的形式转化处理的方法很多,但我觉得QSqlTableModel这个model应算是非常好用的; msql.exec("create table alldata(照片,车牌号 "",入车时间,出车时间,金额,状态,看守人员);"); //创建表格 //msql 打开的数据库即Q…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...