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

JVM类加载机制—JVM类加载过程

一、概述

代码编译后,就会生成JVM(Java虚拟机)能够识别的二进制字节流文件(*.class)。而JVM把Class文件中的类描述数据从文件加载到内存,并对数据进行校验、转换解析、初始化,使这些数据最终成为可以被JVM直接使用的Java类型,这个说来简单但实际复杂的过程叫做JVM的类加载机制。

二、类加载过程

以自定义的Math类为例,分析类加载全过程。实例代码如下:

public class Math {public static final int initData = 666;public static User user = new User();public int compute() { //一个方法对应一块栈帧内存区域int a = 1;int b = 2;int c = (a + b) * 10;return c;}public static void main(String[] args) {Math math = new Math();math.compute();}}

以上面Math类为例,类加载全过程流程如下

1、JVM加载过程分析

其中在JVM中通过类加载器ClassLoader的loadClass方法对类进行装载。loadClass方法加载过程有以下几步:加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载。

1.1 加载

所谓加载不是指的类加载机制,只是类加载机制中的第一步加载。这个阶段就是将Java类的字节码文件加载到机器内存中,并在内存中构建出Java类的原型——类模板对象

类模板对象,其实就是Java类在JVM内存中的一个快照,JVM将从字节码文件中解析出的常量池、类字段、类方法等信息存储到类模板中,这样JVM在运行期便能通过类模板调用Java类中的任意信息。创建的类模板对象的结构存储在方法区中。

一般来说加载分为以下几步:
a. 通过一个类的全限定名(包名与类名)获取此类的二进制字节流(Class文件)。
b.  将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。这里只是转化了数据结构,并未合并数据。(方法区就是用来存放已被加载的类信息,常量,静态变量,编译后的代码的运行时内存区域)
c.  在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。这个Class对象并没有规定是在Java堆内存中,它比较特殊,虽为对象,但存放在方法区中

1.2 验证

验证被加载后的类是否有正确的结构,类数据是否会符合虚拟机的要求,确保不会危害虚拟机安全。

验证作为链接的第一步,用于确保类或接口的二进制表示结构上是正确的,从而确保字节流包含的信息对虚拟机来说是安全的。

Java虚拟机规范中关于验证阶段的规则也是在不断增加的,但大体上会完成下面4个验证动作。

a. 文件格式验证:主要验证字节流是否符合Class文件格式规范,并且能被当前版本的虚拟机处理。
b.  元数据验证:主要对字节码描述的信息进行语义分析,以保证其提供的信息符合Java语言规范的要求。
c. 字节码验证:主要是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。在第二阶段对元数据信息中的数据类型做完校验后,字节码验证将对类的方法体进行校验分析,保证被校验类的方法在运行时不会做出危害虚拟机安全的事件。
d. 符号引用验证:最后一个阶段的校验发生在虚拟机将符号引用转化为直接引用的时候,这个转化动作将在连接的第三阶段解析阶段发生。符号引用是对类自身以外(常量池中的各种符号引用)的信息进行匹配校验。

1.3 准备

给类或接口的静态变量分配内存空间,并且默认初始化这些字段。  并赋予默认值 如 int类型为0,String类型为null, boolean 类型为false等

1.4 解析

将常量池中的符号引用替换为直接引用过程。该阶段会把一些静态方法(符号引用 如main()方法)替换为执行数据所存内存的指针或句柄(直接引用),这就是所谓的静态链接过程(类加载期间完成)。动态链接实在程序运行期间完成的将符号引用替换为直接引用(如 实际使用的方法 math.compute())。

符号引用(Symbolic References):符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要可以唯一定位到目标即可。符号引用于内存布局无关,所以所引用的对象不一定需要已经加载到内存中。各种虚拟机实现的内存布局可以不同,但是接受的符号引用必须是一致的,因为符号引用的字面量形式已经明确定义在Class文件格式中。

直接引用(Direct References):直接引用时直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用和虚拟机实现的内存布局相关,同一个符号引用在不同虚拟机上翻译出来的直接引用一般不会相同。如果有了直接引用,那么它一定已经存在于内存中了。

1.5 初始化

初始化是类加载的最后一步。除了加载阶段,用户可以通过自定义的类加载器参与,其他阶段都完全由虚拟机主导和控制。到了初始化阶段才开始真正执行Java代码。

初始化主要工作就是对类的静态变量初始化为指定的值(如initData = 666)和执行静态代码块。

注意:主类在运行过程中如果使用到其它类,会逐步加载这些类。jar包或war包里的类不是一次性全部加载的,是使用到时才加载。

三、类加载时机

Java虚拟机规范中严格规定了有且只有五种情况必须对类进行初始化

a. 使用new创建类的实例或使用getstatic、putstatic读取或设置一个静态字段的值(放入常量池中的常量除外),以及使用invokestatic调用一个静态方法的时候,对应类必须进行过初始化。

b. 通过java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则要首先进行初始化。

c. 当初始化一个类的时候,如果发现其父类没有进行过初始化,则首先触发父类初始化。

d. 当虚拟机启动时,用户需要指定一个主类(包含main()方法的类),虚拟机会首先初始化这个类。

e. 使用jdk1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、RE_invokeStatic的方法句柄,并且这个方法句柄对应的类没有进行初始化,则需要先触发其初始化。

注意:虚拟机规范使用了“有且只有”这个词描述,这五种情况被称为“主动引用”,除了这五种情况,所有其他的类引用方式都不会触发类初始化,被称为“被动引用”。

1、主动引用情况的示例

new 对象触发类加载

/*** 分析JVM内存模型运行*/
public class Math {private final static int initData = 666;private static User user = new User();public int compute(){       //一个方法对应一个块栈帧内存区域int a = 1;int b = 2;int c = (a + b) * 10;return c;}public static void main(String[] args) {Math m = new Math();int result = m.compute();System.out.println(result);}static {System.out.println(initData);}
}

运行结果

反射触发类加载

示例代码如下

public class ReflectTest {static {System.out.println("ReflectTest static block");}public static void main(String[] args) throws ClassNotFoundException {Class<?> clazz = Class.forName("com.test.jvm.classloader.ReflectTest");}
}

代码运行结果

加载子类会先加载父类

实例代码如下

public class ExtendTest {public static void main(String[] args) {System.out.println(new B().str);}//父类static class A {static {System.out.println("A static block");}}//子类static class B extends A {public String str = "B str";static {System.out.println("B static block");}}
}

示例运行结果

主类触发类加载

示例代码如下

public class HeapTest {private final String str = "0987654321";private final int data = 123456789;public static void main(String[] args) throws InterruptedException {System.out.println("验证堆内存溢出情况");List<HeapTest> heapTestList = new ArrayList<HeapTest>();while (true){HeapTest heapTest = new HeapTest();heapTestList.add(heapTest);//Thread.sleep(10);}}
}

示例运行结果

2、被动引用情况的示例

子类引用父类静态字段

通过子类引用父类的静态字段,对于父类属于“主动引用”的第一种情况,对于子类,没有符合“主动引用”的情况,故子类不会进行初始化。代码如下

public class ExtendTest {public static void main(String[] args) {//System.out.println(new B().str);System.out.println(B.value);}//父类static class A {//静态变量public static int value = 666;static {System.out.println("A static block");}}//子类static class B extends A {public String str = "B str";static {System.out.println("B static block");}}
}

示例运行结果

数组引用类

通过数组来引用类,不会触发类的初始化,因为是数组new,而类没有被new,所以没有触发任何“主动引用”条款,属于“被动引用”。代码如下:

//数组测试类
public class ArrayTest {//静态变量valuepublic static int value = 666;//静态块,父类初始化时会调用static{System.out.println("父类初始化!");}
}//主测试类
public class Test {public static void main(String[] args) {ArrayTest[] tests = new ArrayTest[10];}
}

运行结果

引用静态变量

静态常量在编译阶段就会被存入调用类的常量池中,不会引用到定义常量的类,这是一个特例,需要特别记忆,不会触发类的初始化!

//静态变量测试类
public class ConstClass {static{System.out.println("常量类初始化!");}public static final String HELLOWORLD = "hello world!";
}//主测试类
public class Test {public static void main(String[] args) {//ArrayTest[] tests = new ArrayTest[10];System.out.println(ConstClass.HELLOWORLD);}
}

运行结果

相关文章:

JVM类加载机制—JVM类加载过程

一、概述 代码编译后&#xff0c;就会生成JVM&#xff08;Java虚拟机&#xff09;能够识别的二进制字节流文件&#xff08;*.class&#xff09;。而JVM把Class文件中的类描述数据从文件加载到内存&#xff0c;并对数据进行校验、转换解析、初始化&#xff0c;使这些数据最终成…...

可变参数模板与包装器

抱歉&#xff1a;铁汁们&#xff0c;最近在做兼职&#xff0c;积累社会经验&#xff0c;多有拖欠&#xff0c;请多多包涵&#xff08;抱拳&#xff09; 引子&#xff1a;接上回我们讲了C11的几种新增&#xff0c;今天就来接着讲C11中比较有用的二个东西可变参数模板与包装器。…...

工业控制常用“对象“数据类型汇总(数据结构篇)

合理巧妙的数据结构会大大简化项目的编程工作量,所以任何项目前期第一步应该是设计巧妙的数据结构、封装对象属性。这样会使我们的编程快捷和高效。这篇博客作为数据类型汇总,会不间断更新。 1、普通电机轴对象 2、普通电机轴对象(详细结构变量) TYPE "udtMotorAxis&q…...

优雅处理枚举前端丢失大Long精度问题

1. 枚举-json处理&#xff08;前端 <> 后端 <> 数据库&#xff09; 前端传递 枚举code 后端响应 枚举code 表里存储 枚举code 内存处理 枚举对象 Getter AllArgsConstructor JsonFormat(shape JsonFormat.Shape.OBJECT) public enum SexEnum {MALE(0, "男&…...

【c/c++】 学习ector 容器笔记

c/c 学习ector 容器笔记 int 型的 vector 容器应该使用什么类型的索引&#xff1f; 对于 int 型的 vector 容器&#xff0c;应该使用 size_t 类型的索引。size_t 是一个无符号整数类型&#xff0c;它在标准库中广泛用于表示大小和索引。它足够大&#xff0c;可以表示任何标准…...

DN专业3D图形制作软件win/mac软件安装下载(附下载链接)

目录 一、软件概述 1.1 Adobe DN简介 1.2 Windows/Mac系统要求 Windows系统&#xff1a; Mac系统&#xff1a; 二、安装步骤 2.1 下载与解压 2.2 安装程序 2.3 启动软件 三、使用教程 3.1 界面介绍 3.2 创建和编辑3D内容 3.3 合成与渲染 四、高级技巧与注意事项 …...

VSCode搭建Hzero(SpringCloud架构)后端开发调试环境

正常情况下我们使用IDEA开发Hzero&#xff0c;但是有的公司是不允许破解或者使用IDEA的&#xff0c;此时可以使用eclipse来替代也是可以的&#xff0c;最近尝试使用VSCode来开发调试发现了一些问题其中最大的问题是Vscdoe在绝大多数情况下是不能直接运行Hzero&#xff0c;使用插…...

【C++】OJ习题(初阶)

&#x1f680;个人主页&#xff1a;奋斗的小羊 &#x1f680;所属专栏&#xff1a;C 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 &#x1f4a5;1、字符串&#x1f4a5;1.1 字符串相加&#x1f4a5;1.2 验证回文字符串&#x1f4a5;1.3 反转…...

6.4K+ Star!一个强大的本地知识库问答系统,支持多格式文件和跨语言检索,为企业提供高效、安全的数据洞察……

https://github.com/netease-youdao/QAnything 【阅读原文】跳转Github项目 转自AIGC创想者 项目简介 QAnything 是一个基于本地知识库的问答系统&#xff0c;它能够理解和回答基于任何类型文件的问题。 QAnything支持的文件格式非常广泛&#xff0c;包括PDF、Word、PPT、XL…...

mvn编译的时候出现Perhaps you are running on a JRE rather than a JDK 解决方法

目录 1. 问题所示2. 原理分析3. 解决方法1. 问题所示 mvn编译的时候出现如下问题: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project yudao...

React原理之Fiber详解

前置文章&#xff1a; React原理之 React 整体架构解读React原理之整体渲染流程 -----读懂这一篇需要对 React 整体架构和渲染流程有大致的概念 &#x1f60a;----- 在React原理之 React 整体架构解读中&#xff0c;简单介绍了 Fiber 架构&#xff0c;也了解了 Fiber 节点的…...

远离“优越感”陷阱,拥抱美好人生

在人生的漫长旅程中,我们不断地与他人相遇、相知、相交,在各种关系中寻找温暖、支持与成长。然而,并非所有的关系都如我们所愿,有些关系甚至可能成为我们前进道路上的阻碍。正如我们所知,唯利是图者不可交,但有一种关系比索要金钱更值得警惕,那就是找你索取满足感的关系…...

Redis的线程模型

Redis作为一种基于内存的高性能键值对数据库&#xff0c;其线程模型和IO模型是实现高性能的关键因素。以下将详细探讨Redis的线程与IO模型&#xff0c;内容不少于2000字。 一、Redis的线程模型 Redis的线程模型是理解其高性能的重要基础。在Redis的发展过程中&#xff0c;其线…...

ubuntu24.04安装nginx1.24

ubuntu安装nginx 更新包索引 sudo apt update安装nginx sudo apt install nginx确认安装成功并检查Nginx版本 nginx -v启动Nginx服务 sudo systemctl start nginx设置Nginx开机自启 sudo systemctl enable nginx在浏览器中访问 http://<your_server_IP> 来确认Nginx…...

一款好看的WordPress REST API 主题

介绍&#xff1a; 主题特色&#xff1a; 使用Nuxtjs WordPress Rest Api 实现前后端分离&#xff0c;可完成多端部署&#xff1b; 主题支持自动切换黑夜模式。 使用说明&#xff1a; service 目录为wordpress主题文件&#xff0c;需要拷贝到wordpress主题目录下&#xff0…...

《5G 与区块链融合:智能城市服务质量的飞跃》

在科技飞速发展的时代&#xff0c;5G 技术的普及正以前所未有的速度改变着我们的生活&#xff0c;而区块链技术的兴起也为各领域带来了创新的解决方案。当这两种前沿技术相互结合&#xff0c;将为智能城市的发展注入强大动力&#xff0c;显著提升服务质量&#xff0c;开创更加便…...

前后端分离开发:用 Apifox 高效管理 API

目录 1.前后台分离开发介绍 2.API 2.1 APIfox介绍 2.2 接口文档管理 1.前后台分离开发介绍 前端开发有2种方式&#xff1a;「前后台混合开发」和「前后台分离开发」。 前后台混合开发&#xff0c;顾名思义就是前台后台代码混在一起开发&#xff0c;如下图所示&#xff1a…...

Go Channel 详解

概述 在 Go 语言中&#xff0c;channel 是一种用于在 goroutine 之间传递数据的机制。它提供了同步和通信的能力&#xff0c;使得并发编程变得更加简单和安全。Channel 在 Go 语言中的设计是类型安全的&#xff0c;并且支持发送和接收两种操作。 基本概念 创建通道 创建一个…...

使用FModel提取游戏资产

使用FModel提取游戏模型 前言FModel简介FModel安装FModel使用初次使用资产预览资产导出 附录dumperDumper-7生成usmap文件向游戏中注入dll 前言 这篇文章仅记录我作为初学者使用FModel工具提取某款游戏模型的过程。 FModel简介 FModel是一个开源软件&#xff0c;可以用于查看…...

Qt C++ 屏幕录制 保存mp4

在麒麟系统&#xff08;基于 Linux&#xff09;上优化 Qt C 的屏幕录制&#xff0c;主要针对捕获效率和编码速度。可以参考以下优化策略&#xff1a; 1. 使用更高效的屏幕捕获 API 麒麟系统作为 Linux 系统的一种&#xff0c;可以考虑直接使用 X11、Wayland、或 DRM/KMS API …...

Adobe After Effects的插件--------CC Cylinder

CC Cylinder是柱体插件。它是AE内置的3D插件。 使用条件 该插件的作用是将2D图层转换为3D的柱体。所以使用该插件时要确保源图层为2D的。 我们以一张图片素材为例: 给图片图层添加CC Cylinder效果控件,然后新建一个摄像机(利用摄像机旋转、平移、推拉工具,方便在各个角度…...

Vue3项目开发——新闻发布管理系统(一)

文章目录 一、项目要实现的功能二、项目用到的技术栈三、项目创建1、pnpm安装2、创建项目3、项目启动四、项目配置1、ESLint2、Prettier3、ESLint + Prettier 进行配置代码风格3.1配置prettier3.2vue组件名称多单词组成 (忽略index.vue)3.3props解构(关闭)4、husky4.1husky…...

前端调用后端,出现跨域报错怎么办

我前端是vue&#xff0c;后端是其他同事写的python&#xff0c;因为部署在不同的机器上&#xff0c;我前端如果直接调用他的python&#xff0c;axios请求就会出现跨域报错&#xff0c;如下 blocked by CORS policy 云云 怎么办呢&#xff0c;网上探索了一下午&#xff0c;才找…...

使用Node-RED发送数据到巴法云

上一篇博文完成了Node-RED的安装&#xff0c;下面来尝试一下用Node-RED来发送数据到巴法云服务器。 我在教学用MQTT工具的思考-CSDN博客中说过&#xff0c;巴法云支持云云互联&#xff0c;可以连小米、百度&#xff0c;学生使用的兴趣高。所以今天先测试Node-RED和巴法云的连接…...

【今夕是何年】雅达利发布Atari 7800+游戏主机:配备无线手柄、HDMI接口

雅达利&#xff08;Atari&#xff09;发布了Atari 7800游戏主机&#xff0c;目前这款主机在其官方商城接受预定&#xff0c;售价129.99美元。Atari 7800游戏主机&#xff0c;作为Atari 7800系列的革新升级版本&#xff0c;搭载了高效的Rockchip 3128处理器&#xff0c;不仅确保…...

APP支付宝授权获取code uniapp

1.点击使用plus.runtime跳转打开支付宝 //打开支付宝授权&#xff0c;在支付宝APP中授权后会在支付宝中跳转到你填写的h5地址//urls是授权地址可以后端拼接也可以前端写死 //以下是一个拼接示例&#xff0c;需修改app_id的值和redirect_uri的值即可 //app_id是商户的APPID&…...

在Linux系统下安装、配置ETCD

在Linux系统下安装、配置ETCD&#xff08;一个分布式键值存储系统&#xff09;涉及多个步骤&#xff0c;包括下载、安装、配置、启动以及使用ETCD的常用命令。以下是对这些步骤的详细讲解&#xff0c;内容不少于2000字。 一、ETCD简介 ETCD是一个高可用的键值存储系统&#x…...

lambda 表达式可以传递引用为什么需要引用捕获

当 lambda 表达式被传递或存储在其他地方时&#xff0c;通过引用捕获可以确保它始终访问正确的外部变量。—— 引用捕获可以精确地控制被捕获的引用变量的作用域。如果一个 lambda 表达式被存储在一个容器中&#xff0c;并且在不同的时间点被调用&#xff0c;引用捕获可以确保它…...

【Java】/* 双向链表 - 底层实现 */

【难点】&#xff1a;remove、removeAllKey 一、IList package bagfive;/*** Created with IntelliJ IDEA.* Description:* User: tangyuxiu* Date: 2024-08-21* Time: 20:30*/ public interface IList<E> {//头插法void addFirst(E data);//尾插法void addLast(E data…...

Go 语言协程管理精解

1.基础 协程切换需要操作寄存器&#xff0c;这些操作需要通过汇编辅助实现。另外&#xff0c;每一个协程都有一个协程栈&#xff0c;实际上协程栈也是有结构的。汇编程序和栈结构这些概念可能大部分开发者都不太了解&#xff0c;在介绍协程管理之间&#xff0c;先简要介绍。 1…...

网站建设推广销售好做吗/贵阳网站建设

华为emui10.1系统正式版跟随这次p40系列新品发布会一起到来了&#xff0c;全新升级的版本打造&#xff0c;为新款手机提供了更为优质的软件使用体验&#xff0c;有效结合了硬件的优质&#xff0c;更好地发挥了手机的强大功能&#xff0c;实现了更为高效的操作功能服务&#xff…...

优质的专业网站建设/seo排名怎么看

本文是对 质点同学 的圆锥曲线的三维矢量解法系列文章的补充。本文会不定期更新&#xff0c;如果我想到有价值的新内容的话。【在一条直线上的点列】我们知道已知两点 &#xff0c;它们的连线 &#xff0c;我们用两个点矢量叉乘可以得到一个线矢量。但是我们还想用这个两个点矢…...

河间市做网站/徐州百度seo排名

&#x1f4e2;前言&#x1f332;原题样例&#xff1a;Excel 表列序号&#x1f33b;C#方法&#xff1a;深度优先搜索&#x1f33b;Java 方法一&#xff1a;二分查找&#x1f4ac;总结&#x1f680;往期优质文章分享&#x1f4e2;前言 &#x1f680; 算法题 &#x1f680; &…...

正规网站开发流程/外贸推广方式都有哪些

# 函数a [1, 3, 6, 4, 85, 32, 46]print(sum(a)) # sum&#xff0c;求和函数def add():a 1,b 2,return a bprint(add())def add(a, b): # 都必填return a bprint(add())def add(a0, b0): # 都非必填return a bprint(add())def add(a, b0): # a必填(必填项放前面)return a…...

哈尔滨做网站电话/小时seo

2019独角兽企业重金招聘Python工程师标准>>> SAP HANA SPS 08新特性资料汇总 HANA(High-Performance Analytic Appliance)高性能分析设备。那么SAP HANA SPS 08针对07版本又有哪些改进呢&#xff1f;本文集将为大家汇总和持续更新这一系列的资料。 详细解读 和小伙伴…...

asp绿色简洁通用型企业网站源码/百度seo搜索引擎优化培训

点击下载 FileDown.zip 主要功能如下 1.参数为虚拟路径 2.获取物理地址 3.普通下载 4.分块下载 5.输出硬盘文件&#xff0c;提供下载 支持大文件、续传、速度限制、资源占用小 看下面代码吧 /// <summary> /// 编 码 人&#xff1a;苏飞 /// 联系方式&#xff1a;3619836…...