【JVM】类加载的过程
文章目录
- 类的生命周期
- 加载
- 验证
- 准备
- 解析
- 初始化
- 简要概括
类的生命周期
一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历加载 (Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化 (Initialization)、使用(Using)和卸载(Unloading)七个阶段,其中验证、准备、解析三个部分统称 为连接(Linking)。
加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类型的加载过程必须按照这种顺序按部就班地开始(是开始不是完成),而解析阶段则不一定:它在某些情况下可以在初始化阶段之后再开始, 这是为了支持Java语言的运行时绑定特性(也称为动态绑定或晚期绑定)。
加载
在加载阶段,Java虚拟机需要完成以下三件事情:
-
通过一个类的全限定名来获取定义此类的二进制字节流。
-
将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
-
在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
不同的虚拟机实现细节有所不同
验证
验证是连接阶段的第一步,这一阶段的目的是确保Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。
验证阶段大致上会完成下面四个阶段的检验动作:
-
文件格式验证:首先验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理,例如是否以魔数0xCAFEBABE开头。主、次版本号是否在当前Java虚拟机接受范围之内。等
-
元数据验证:第二阶段是对字节码描述的信息进行语义分析、校验,以保证其描述的信息符合《Java语言规范》的要求,例如这个类是否有父类,这个类的父类是否继承了不允许被继承的类,如果这个类不是抽象类,是否实现了其父类或接口之中要求实现的所有方法等等
-
字节码验证:第三阶段是整个验证过程中最复杂的一个阶段,主要目的是通过数据流分析和控制流分析,确定序语义是合法的、符合逻辑的。例如保证任何跳转指令都不会跳转到方法体以外的字节码指令上,例如不会出现类似于“在操作栈放置了一个int类型的数据,使用时却按long类型来加载入本地变量表中”这样的情况等等
-
符号引用验证:最后一个阶段的校验行为发生在虚拟机将符号引用转化为直接引用的时候,这个转化动作将在连接的第三阶段—解析阶段中发生。通俗来说就是,该类是否缺少或者被禁止访问它依赖的某些外部类、方法、字段等资源。例如符号引用中通过字符串描述的全限定名是否能找到对应的类,在指定类中是否存在符合方法的字段描述符及简单名称所描述的方法和字段等等
准备
准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段,这时候进行内存分配的仅包括类变量,而不包括实例变量。
类变量在准备阶段之后的默认值如下
public static int value = 123
对于上面代码,在准备阶段之后value的值为0,而不是123,把value赋值为123指令存放于类构造器<client>()方法之中,要到类的初始化阶段才会被执行。
如果类字段的字段属性表中存在ConstantValue属性,那在准备阶段变量值就会被初始化为ConstantValue属性所指定的初始值
public static final int value = 123;
上面使用了final修饰value,那么value在准备阶段之后就是123了,不会使用默认值。
解析
解析阶段是Java虚拟机将常量池内的符号引用替换为直接引用的过程,这句话的具体解释如下
- 符号引用(Symbolic Reference):在Java源代码中,类和成员(字段、方法)的引用通常以符号引用的形式存在。这些引用是一种符号性的标识,指向了目标类或成员的名字、描述符等信息。例如,
String
类型的字段引用可能是Ljava/lang/String;
这样的描述。 - 直接引用(Direct Reference):与符号引用不同,直接引用是一个指向内存位置的指针或句柄,它可以直接用于访问目标类或成员的内存地址。直接引用是实际的内存指针或句柄,可以直接执行实际操作。
- 解析(Resolution):解析是将符号引用转化为直接引用的过程。在Java类加载过程中,虚拟机需要知道如何定位并访问目标类或成员,因此需要将符号引用解析为直接引用。这通常涉及到查找目标类的内存地址、方法的内存偏移量等信息。
- 可选性:解析阶段在类加载过程中是可选的。这意味着不是每个类加载过程都需要执行解析。解析通常在需要使用某个类或成员的时候才会进行,而且某些情况下,虚拟机可能会跳过解析,直接使用符号引用来访问目标。
总结来说,解析是将类或成员的符号引用转化为直接引用的过程,但它并不一定在每次加载类时都执行。虚拟机可能会延迟解析,只在需要的时候执行,以提高性能和节省资源。这个过程有助于虚拟机在运行时准确访问类或成员的内存位置。
举一个简单的例子如下
public class MathUtil {public static int add(int a, int b) {return a + b;}
}
public class Test {public static void main(String[] args) {int result = MathUtil.add(5, 3);System.out.println("Result: " + result);}
}
在Test类中,MathUtil.add(5, 3)
是一个符号引用,它指向了 MathUtil
类和 add
方法,但它并没有直接指向方法的内存地址或偏移量。
解析阶段会将这个符号引用转化为直接引用,以便能够执行实际的方法调用。这个过程涉及查找 MathUtil
类的内存地址,并获取 add
方法的内存偏移量。一旦解析完成,就可以直接调用 add
方法的内存地址
初始化
简单来说初始化阶段就是执行类构造器<client()>方法的过程。
<client()>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序决定的,静态语句块中只能访问 到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问
public class Test {static {i = 0; // 给变量复制可以正常编译通过System.out.print(i); // 这句编译器会提示“非法向前引用”}static int i = 1;
}
<client()>()方法对于类或接口来说并不是必需的,如果一个类中没有静态语句块,也没有对变量的赋值操作,那么编译器可以不为这个类生成<client()>()方法
Java虚拟机必须保证一个类的<client()>()方法在多线程环境中被正确地加锁同步,如果多个线程同 时去初始化一个类,那么只会有其中一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行完毕<client()>()方法。
《Java虚拟机规范》 严格规定了有且只有六种情况必须立即对类进行“初始化”
- 遇到new、getstatic、putstatic或invokestatic这四条字节码指令时,如果类型没有进行过初始化,则需要先触发其初始化阶段。
- 使用java.lang.reflect包的方法对类型进行反射调用的时候,如果类型没有进行过初始化,则需要先触发其初始化。
- 当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
- 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。
- 如果一个java.lang.invoke.MethodHandle实例最后的解 析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句 柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化。
- 当一个接口中定义了JDK 8新加入的默认方法(被default关键字修饰的接口方法)时,如果有这个接口的实现类发生了初始化,那该接口要在其之前被初始化。
简要概括
类加载过程分为以下几个简单的阶段:
- 加载(Loading):从磁盘或网络加载类的字节码到内存,形成类的结构。
- 验证(Verification):确保加载的字节码合法且不包含安全风险。
- 准备(Preparation):为类的静态变量分配内存并初始化为默认值。
- 解析(Resolution,可选):将符号引用转化为直接引用,以便正确访问类和成员。
- 初始化(Initialization):执行类的初始化代码,包括静态初始化块和静态字段的赋值。
这些阶段确保了类在运行时能够被正确加载和使用。其中,解析是可选的,其他阶段通常都会执行。
相关文章:

【JVM】类加载的过程
文章目录 类的生命周期加载验证准备解析初始化简要概括 类的生命周期 一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历加载 (Loading)、验证(Verification)、准备…...
Golang 结构化日志包 log/slog 详解(四):分组、上下文和属性值类型
上一篇文章讲解了 log/slog 包中的自定义日志属性字段和日志级别,本文讲解下分组、上下文和属性值类型 分组输出 slog 支持将字段放在组中并且可以给分组指定名称。如何展示分组的内容,取决于使用的 handler,例如 TextHandler 使用点号分隔…...

小白学Python:提取Word中的所有图片,只需要1行代码
#python# 大家好,这里是程序员晚枫,全网同名。 最近在小破站账号:Python自动化办公社区更新一套课程:给小白的《50讲Python自动化办公》 在课程群里,看到学员自己开发了一个功能:从word里提取图片。这个…...
pip修改位于用户目录下的缓存目录
默认 pip 缓存目录: Windows: C:\Users\${用户名}\AppData\Local\pip\cache Linux: ~/.cache/pip 一、修改方式 1.命令方式 pip config set global.cache-dir "D:\kwok\data\pip-cache" 2.配置文件方式 ① Windows: C:\Users\${用…...

更新、修改
MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129334507?spm1001.2014.3001.5502 语法: update 表名 列名该列新值, 列名该列新值, ... where 记录匹配条件; 说明:update 更新、修改 set 设置 …...

山西电力市场日前价格预测【2023-09-25】
日前价格预测 预测说明: 如上图所示,预测明日(2023-09-25)山西电力市场全天平均日前电价为442.30元/MWh。其中,最高日前电价为720.46元/MWh,预计出现在19: 00。最低日前电价为276.06元/MWh,预计…...
从collections库的Counter类看items()方法和enumerate()方法
下面的代码是针对文件的词频统计,使用了collections库及其Counter类 import collections def count_word_frequency(text): words text.lower().split() word_counts collections.Counter(words) return word_counts def count_fileword_frequency(fi…...
2023-09-24 LeetCode每日一题(LRU 缓存)
2023-09-24每日一题 一、题目编号 146. LRU 缓存二、题目链接 点击跳转到题目位置 三、题目描述 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存i…...

《计算机视觉中的多视图几何》笔记(10)
10 3D Reconstruction of Cameras and Structure 本章主要描述了如何利用2张图片来恢复相机的参数以及物体在三维空间中的形状。 文章目录 10 3D Reconstruction of Cameras and Structure10.1 Outline of reconstruction method10.2 Reconstruction ambiguity10.3 The proje…...

【一、虚拟机vmware安装】
安装虚拟机 下载 官方下载地址:https://www.vmware.com/cn.html 大概流程就是,最重要的事最后一步...

uniapp 离线打包 plus.runtime.install 安装页面不弹起
uniapp 离线打包 plus.runtime.install 安装页面不弹起 updateVersion(webview : any, eventTitle : string, eventContent : string) {const loading plus.nativeUI.showWaiting(准备下载);var dtask plus.downloader.createDownload(eventContent,{method: GET,timeout: 5…...

Docker 自动化部署(保姆级教程)
Docker 自动化部署 1. jenkins 介绍1.1 参考链接:1.2 jenkins 概述1.3 jenkins部署项目的流程 2. jenkins 安装2.1 基于docker 镜像2.2 启动 jenkins 后端服务2.3 登录 jenkins 服务后端 3. jenkins自动化部署开始3.1 下载需要的插件3.2 创建任务3.2.1 描述3.2.2 配…...

北工大汇编题——分支程序设计
题目要求 信息检素程序设计:在数据区,有9个不同的信息,编号 0-8,每个信息包括20 个字符。从键盘接收 0-8 之间的一个编号,然后再屏幕上显示出相应编号的信息内容,按“q”键退出 完整代码 DATAS SEGMENTn0…...

贴片电容耐压值选取和特性(包含实际电路和PCB)
一、一般电容的特性 ①容值大的电容,一般通低频率; ②容值小的电容,一般通高频率。 注:详细请看这位博主的篇文章: 大电容为什么虑低频小电容为什么又虑高频?(个人整理) 二、贴片电容的耐压选取 ①贴片电容有2…...
【云原生】kubernetes中pod(进阶)
目录 一、资源限制 业务cpu 内存 1.1CPU 资源单位 1.2 内存 资源单位 示例1 示例2: 二、健康检查:又称为探针(Probe) 2.1探针的三种规则 2.2 Probe支持三种检查方法 2.3示例 示例1:exec方式 示例3…...
Cesium 问题:获取高度值,高度值又是相对于谁来说的
文章目录 问题分析 问题 今天在开发中,甲方提出一个这样的问题,你的高度是怎么算出来的,对此,我只知道使用并不知道怎么来的,因此特意查了一番资料,希望帮助到大家 分析 在 Cesium 中,我们可以使…...
第三、四、五场面试
第三场 共享屏幕做题(三道简单题) 替换空格成%20(双指针) 删除升序链表中的重复元素(指针)有效的括号(栈) 第四场、第五场 自我介绍 项目拷打 整个项目架构rpc模块的情况分析的数…...

力扣-290.单词规律
Idea 先建立一个hashmap,记录s串中的每个单词以及对应的下标再建立一个hashmap,记录pattern串中相同字母以及对应的下标遍历pattern串时,遇到不同字母存到pat表中,同时将下标对应的s中的单词存入到查重test集中,因为如…...

常见限流算法学习
文章目录 常见限流算法学习前言限流算法基本介绍固定窗口计数器限流算法计数器限流算法相关介绍计数器限流算法的实现(基于共享变量)计数器限流算法的实现(基于Redis) 滑动窗口计数器算法滑动时间窗口算法相关介绍介绍滑动时间窗口…...
JS面试相关
深拷贝、浅拷贝、递归、优化 扁平化 柯里化 this指向原型 继承 call、apply、bind js取整的方法,parseInt第二个参数是什么 forEach和map有什么区别,使用场景? 内存泄漏的场景 原型链原型 严格模式 Js中for in 和for of的区别 slice、splice、…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...