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

【JVM】类加载的过程

文章目录

  • 类的生命周期
  • 加载
  • 验证
  • 准备
  • 解析
  • 初始化
  • 简要概括

类的生命周期

一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历加载 (Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化 (Initialization)、使用(Using)和卸载(Unloading)七个阶段,其中验证、准备、解析三个部分统称 为连接(Linking)。

image-20230921154106541

加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类型的加载过程必须按照这种顺序按部就班地开始(是开始不是完成),而解析阶段则不一定:它在某些情况下可以在初始化阶段之后再开始, 这是为了支持Java语言的运行时绑定特性(也称为动态绑定或晚期绑定)。

加载

在加载阶段,Java虚拟机需要完成以下三件事情:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流。

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

  3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

不同的虚拟机实现细节有所不同

验证

验证是连接阶段的第一步,这一阶段的目的是确保Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。

验证阶段大致上会完成下面四个阶段的检验动作:

  • 文件格式验证:首先验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理,例如是否以魔数0xCAFEBABE开头。主、次版本号是否在当前Java虚拟机接受范围之内。等

  • 元数据验证:第二阶段是对字节码描述的信息进行语义分析、校验,以保证其描述的信息符合《Java语言规范》的要求,例如这个类是否有父类,这个类的父类是否继承了不允许被继承的类,如果这个类不是抽象类,是否实现了其父类或接口之中要求实现的所有方法等等

  • 字节码验证:第三阶段是整个验证过程中最复杂的一个阶段,主要目的是通过数据流分析和控制流分析,确定序语义是合法的、符合逻辑的。例如保证任何跳转指令都不会跳转到方法体以外的字节码指令上,例如不会出现类似于“在操作栈放置了一个int类型的数据,使用时却按long类型来加载入本地变量表中”这样的情况等等

  • 符号引用验证:最后一个阶段的校验行为发生在虚拟机将符号引用转化为直接引用的时候,这个转化动作将在连接的第三阶段—解析阶段中发生。通俗来说就是,该类是否缺少或者被禁止访问它依赖的某些外部类、方法、字段等资源。例如符号引用中通过字符串描述的全限定名是否能找到对应的类,在指定类中是否存在符合方法的字段描述符及简单名称所描述的方法和字段等等

准备

准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段,这时候进行内存分配的仅包括类变量,而不包括实例变量。

类变量在准备阶段之后的默认值如下

image-20230921163134041

public static int value = 123

对于上面代码,在准备阶段之后value的值为0,而不是123,把value赋值为123指令存放于类构造器<client>()方法之中,要到类的初始化阶段才会被执行。

如果类字段的字段属性表中存在ConstantValue属性,那在准备阶段变量值就会被初始化为ConstantValue属性所指定的初始值

public static final int value = 123;

上面使用了final修饰value,那么value在准备阶段之后就是123了,不会使用默认值。

解析

解析阶段是Java虚拟机将常量池内的符号引用替换为直接引用的过程,这句话的具体解释如下

  1. 符号引用(Symbolic Reference):在Java源代码中,类和成员(字段、方法)的引用通常以符号引用的形式存在。这些引用是一种符号性的标识,指向了目标类或成员的名字、描述符等信息。例如,String类型的字段引用可能是 Ljava/lang/String; 这样的描述。
  2. 直接引用(Direct Reference):与符号引用不同,直接引用是一个指向内存位置的指针或句柄,它可以直接用于访问目标类或成员的内存地址。直接引用是实际的内存指针或句柄,可以直接执行实际操作。
  3. 解析(Resolution):解析是将符号引用转化为直接引用的过程。在Java类加载过程中,虚拟机需要知道如何定位并访问目标类或成员,因此需要将符号引用解析为直接引用。这通常涉及到查找目标类的内存地址、方法的内存偏移量等信息。
  4. 可选性:解析阶段在类加载过程中是可选的。这意味着不是每个类加载过程都需要执行解析。解析通常在需要使用某个类或成员的时候才会进行,而且某些情况下,虚拟机可能会跳过解析,直接使用符号引用来访问目标。

总结来说,解析是将类或成员的符号引用转化为直接引用的过程,但它并不一定在每次加载类时都执行。虚拟机可能会延迟解析,只在需要的时候执行,以提高性能和节省资源。这个过程有助于虚拟机在运行时准确访问类或成员的内存位置。

举一个简单的例子如下

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虚拟机规范》 严格规定了有且只有六种情况必须立即对类进行“初始化”

  1. 遇到new、getstatic、putstatic或invokestatic这四条字节码指令时,如果类型没有进行过初始化,则需要先触发其初始化阶段。
  2. 使用java.lang.reflect包的方法对类型进行反射调用的时候,如果类型没有进行过初始化,则需要先触发其初始化。
  3. 当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
  4. 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。
  5. 如果一个java.lang.invoke.MethodHandle实例最后的解 析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句 柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化。
  6. 当一个接口中定义了JDK 8新加入的默认方法(被default关键字修饰的接口方法)时,如果有这个接口的实现类发生了初始化,那该接口要在其之前被初始化。

简要概括

类加载过程分为以下几个简单的阶段:

  1. 加载(Loading):从磁盘或网络加载类的字节码到内存,形成类的结构。
  2. 验证(Verification):确保加载的字节码合法且不包含安全风险。
  3. 准备(Preparation):为类的静态变量分配内存并初始化为默认值。
  4. 解析(Resolution,可选):将符号引用转化为直接引用,以便正确访问类和成员。
  5. 初始化(Initialization):执行类的初始化代码,包括静态初始化块和静态字段的赋值。

这些阶段确保了类在运行时能够被正确加载和使用。其中,解析是可选的,其他阶段通常都会执行。

相关文章:

【JVM】类加载的过程

文章目录 类的生命周期加载验证准备解析初始化简要概括 类的生命周期 一个类型从被加载到虚拟机内存中开始&#xff0c;到卸载出内存为止&#xff0c;它的整个生命周期将会经历加载 &#xff08;Loading&#xff09;、验证&#xff08;Verification&#xff09;、准备&#xf…...

Golang 结构化日志包 log/slog 详解(四):分组、上下文和属性值类型

上一篇文章讲解了 log/slog 包中的自定义日志属性字段和日志级别&#xff0c;本文讲解下分组、上下文和属性值类型 分组输出 slog 支持将字段放在组中并且可以给分组指定名称。如何展示分组的内容&#xff0c;取决于使用的 handler&#xff0c;例如 TextHandler 使用点号分隔…...

小白学Python:提取Word中的所有图片,只需要1行代码

#python# 大家好&#xff0c;这里是程序员晚枫&#xff0c;全网同名。 最近在小破站账号&#xff1a;Python自动化办公社区更新一套课程&#xff1a;给小白的《50讲Python自动化办公》 在课程群里&#xff0c;看到学员自己开发了一个功能&#xff1a;从word里提取图片。这个…...

pip修改位于用户目录下的缓存目录

默认 pip 缓存目录&#xff1a; Windows: C:\Users\${用户名}\AppData\Local\pip\cache Linux: ~/.cache/pip 一、修改方式 1.命令方式 pip config set global.cache-dir "D:\kwok\data\pip-cache" 2.配置文件方式 ① Windows&#xff1a; C:\Users\${用…...

更新、修改

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

山西电力市场日前价格预测【2023-09-25】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-09-25&#xff09;山西电力市场全天平均日前电价为442.30元/MWh。其中&#xff0c;最高日前电价为720.46元/MWh&#xff0c;预计出现在19: 00。最低日前电价为276.06元/MWh&#xff0c;预计…...

从collections库的Counter类看items()方法和enumerate()方法

下面的代码是针对文件的词频统计&#xff0c;使用了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 类&#xff1a; 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安装】

安装虚拟机 下载 官方下载地址&#xff1a;https://www.vmware.com/cn.html 大概流程就是&#xff0c;最重要的事最后一步...

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 参考链接&#xff1a;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 配…...

北工大汇编题——分支程序设计

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

贴片电容耐压值选取和特性(包含实际电路和PCB)

一、一般电容的特性 ①容值大的电容&#xff0c;一般通低频率&#xff1b;  ②容值小的电容&#xff0c;一般通高频率。   注&#xff1a;详细请看这位博主的篇文章&#xff1a; 大电容为什么虑低频小电容为什么又虑高频?(个人整理) 二、贴片电容的耐压选取 ①贴片电容有2…...

【云原生】kubernetes中pod(进阶)

目录 一、资源限制 业务cpu 内存 1.1CPU 资源单位 1.2 内存 资源单位 示例1 示例2&#xff1a; 二、健康检查&#xff1a;又称为探针&#xff08;Probe&#xff09; 2.1探针的三种规则 2.2 Probe支持三种检查方法 2.3示例 示例1&#xff1a;exec方式 示例3&#xf…...

Cesium 问题:获取高度值,高度值又是相对于谁来说的

文章目录 问题分析 问题 今天在开发中&#xff0c;甲方提出一个这样的问题&#xff0c;你的高度是怎么算出来的&#xff0c;对此&#xff0c;我只知道使用并不知道怎么来的&#xff0c;因此特意查了一番资料&#xff0c;希望帮助到大家 分析 在 Cesium 中&#xff0c;我们可以使…...

第三、四、五场面试

第三场 共享屏幕做题&#xff08;三道简单题&#xff09; 替换空格成%20&#xff08;双指针&#xff09; 删除升序链表中的重复元素&#xff08;指针&#xff09;有效的括号&#xff08;栈&#xff09; 第四场、第五场 自我介绍 项目拷打 整个项目架构rpc模块的情况分析的数…...

力扣-290.单词规律

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

常见限流算法学习

文章目录 常见限流算法学习前言限流算法基本介绍固定窗口计数器限流算法计数器限流算法相关介绍计数器限流算法的实现&#xff08;基于共享变量&#xff09;计数器限流算法的实现&#xff08;基于Redis&#xff09; 滑动窗口计数器算法滑动时间窗口算法相关介绍介绍滑动时间窗口…...

JS面试相关

深拷贝、浅拷贝、递归、优化 扁平化 柯里化 this指向原型 继承 call、apply、bind js取整的方法&#xff0c;parseInt第二个参数是什么 forEach和map有什么区别&#xff0c;使用场景&#xff1f; 内存泄漏的场景 原型链原型 严格模式 Js中for in 和for of的区别 slice、splice、…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...