聊聊Java虚拟机(一)—— 类加载子系统

1. 前言

​ 虚拟机就是一款用来执行虚拟计算机指令的计算机软件。它相当于一台虚拟计算机。大体上,虚拟机分为系统虚拟机和程序虚拟机。系统虚拟机就相当于一台物理电脑,里面可以安装操作系统;程序虚拟机是为了执行单个计算机程序而设计出来的虚拟机。其中 Java 虚拟机就是执行 Java 字节码指令的虚拟机

JVM 是什么?

java 虚拟机是运行在各大平台的执行字节码文件的虚拟计算机。如下图所示

这样的设计可以让编译后的代码在各个操作平台上运行。

JVM 的位置

JVM 在 Java 体系结构中的位置

从用户操作角度看 JVM 所处的位置

JVM 与实际的计算机硬件没有交互,它们中间还有个操作系统,调用硬件需要通过操作系统来实现。

JVM 的结构

JVM 的整体运行结构

本文主要针对于 Hotspot VM 来进行,其结构如下所示:

JVM 的指令结构

JVM 是基于栈的指令集架构,跟基于寄存器的指令集不同。它是一个步骤一个一条指令。

//基于栈的指令集
iconst_2 //常量2入栈
istore_1
iconst_3 // 常量3入栈
istore_2
iload_1
iload_2
iadd //常量2/3出栈,执行相加
istore_0 // 结果5入栈
//基于寄存器的指令集
mov eax,2 //在eax寄存器中的值设为2
add eax,3 //将eax寄存器中的值加3   

举例说明:

/**
 * @author wjw
 * @date 11/3/2021
 */
public class StackStruTest {
    public static void main(String[] args) {
        int i = 2 + 3;
        /**
         *0: iconst_5
         *1: istore_1
         *2: return
         */
        int i = 2;
        int j = 3;
        int k = i + j;
        /**
         * 0: iconst_2
         * 1: istore_1
         * 2: iconst_3
         * 3: istore_2
         * 4: iload_1
         * 5: iload_2
         * 6: iadd
         * 7: istore_3
         * 8: return
         */
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("hello");
    }
}

JVM 的生命周期

JVM 的启动

Java 的启动是通过引导类加载器(BootStrap ClassLoader)创建一个初始类(java.lang.class)来实现的,也就是后面要提到的子类加载器过程。

JVM 的执行

执行 Java 的字节码文件中的各个方法和类的过程。

JVM 的退出

  • 程序正常执行结束
  • 操作系统终止 JVM 进程终止
  • 某线程调用 Runtime.exit() 或 System.halt() 方法
  • 程序执行过程异常或错误而终止退出

2. 类加载子系统的主要流程

让我们先看看一个 java 程序执行的流程是怎样的:

  • 首先一个 java 文件编写完后,经过 java 编译器生成 .class 文件
  • 这个 .class 文件经过类加载器,加载各类的 jar 包,以及该程序所需要的三方类的 .class 文件。并生成 java.lang.class 对象,这个对象将作为程序访问方法区中的这些类型数据的外部接口
  • . class 文件经过解析执行和 JIT 编译器编译执行,并调用操作系统相关指令来完成 java 程序。

而类加载子系统涉及到的过程有类加载器、字节码校验器和翻译字节码这几个过程:

加载阶段(Loading)

加载阶段(Loading)是类加载阶段(Class Loading)的一部分。在加载阶段中,.class 文件将经过三个类加载器的加载后才能进入下一个阶段。该阶段主要的作用(也就是上面 java 程序执行中的类加载器阶段)有:

  • 将各种各样格式的 .class 文件(jar 包,网络中,动态代理等等)读取并生成一个字节流,并转换成方法区中的运行时数据结构
  • 在内存中生成一个 java.lang.Class 对象,这个对象将作为程序访问方法区中的这些类型数据的外部接口

在类加载器中,主要分为两类:引导类加载器自定义类加载器

引导类加载器(Bootstrap ClassLoader)
  • 使用的是 C/C++ 来实现的,无法访问到,调用getClassLoader() 函数是为null。

  • 加载的类是一些核心类库,lib/home 下的类库。比如说是 Object 、String 等等 JVM 自身运行需要的类

  • 是其他加载器的父类吗?是的,但是无父类加载器

自定义类加载器(User-Defined ClassLoader)

派生于抽象类 ClassLoader 的类加载器

  • (1)拓展类加载器(Extension ClassLoader)

    • 父类加载器为 BootStrap ClassLoader

    • 主要加载的类是ext 文件夹下的类库

  • (2)应用程序类加载器(AppClassLoader)

    • 父类加载器为 Extension ClassLoader

    • 主要加载的是环境变量 classpath 或系统属性 java.class.path 指定路径下的类库

    • 程序中默认的类加载器

  • (3) 自定义类加载器

    • extCassLoader 和 AppClassLoader 是 sun.misc.Launcher 的两个内部类

为了防止虚拟机内部的核心类库的修改和非法调用,JVM 的设计者们在类加载过程中设计出了双亲委派机制沙箱安全机制

双亲委派机制
  • 当前类加载器先不加载,先委托其父类加载器,依次到启动加载器
  • 如果启动加载器还没找到所要的类,然后向下查找,到返回到最初的子类加载器
  • 类加载器之间的关系不是继承,而是通过组合来复用父加载器的代码。

举例

  • 首先在 Bootstrap ClassLoader 中加载核心 rt.jar 包中的核心类
  • 核心类中的一些三方接口在反向委派到应用程序加载器加载第三方的 jar 包
  • 是通过当前线程加载器(就是系统类加载器)加载到 jdbc.jar 包中的 SPI 接口实现类

双亲委派机制的优点:

  • 避免类的重复加载
  • 保护程序安全,防止核心 API 被随意篡改
沙箱安全机制

引导类加载器在加载时会首先加载 JDK 中自带的文件。报错信息中没有相应方法时的机制。保证对 java 核心源代码的保护。

链接阶段(Linking)
验证(Verify)

验证字节流文件中的相关信息,确认当前文件符合虚拟机的相关格式(文件、元数据、符号等等)。

准备(Prepare)

在方法区中为类变量分配内存并设置类变量初始值

  • 这里的类变量是指被 static 修饰的变量,不包括实例变量(实例变量在对象实例化时随着对象一起分配)
  • 初始值指的是数据类型的零值
解析(Resolve)
  • 虚拟机将常量池中的符号引用转换成直接引用(class 文件很小,先存放指向所需要类的符号,解析时再引用)

  • 针对类、接口、字段方法等7类符号引用进行转换

  • 没有规定解析阶段发生的具体时间,也可能在初始化阶段的后面

初始化阶段(Initiation)
  • 初始化过程实际上就是执行类构造器方法 ( ) 的过程

    • 它是 javac 编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来,不需要定义。
    public class ClassInitTest {
        private static int num = 1;
    
        static {
            num = 2;
            number = 20;
            System.out.println(num);//因为在linking 阶段中的 Prepare 阶段已经给静态变量赋过初始值了。
            //非法的前向引用;在声明变量之前,可以去给这些变量进行赋值,但是不能够调用它。
            //System.out.println(number);//会报错误
        }
    
        /**也就是在 linking 中的 prepare 中对变量进行默认赋值为0
         * 此时initial 给予其一个覆盖从 20 到 10
         *
         */
        private static int number = 10;
    
        public static void main(StringDemo[] args)
        {
            System.out.println(ClassInitTest.num);
            System.out.println(ClassInitTest.number);
        }
    }
    
    • 它不需要显示调用父类构造器,在子类的( ) 执行前,父类的 ( ) 方法早已执行完毕。

  • 构造器方法执行是按语句顺序来执行的。

  • 类构造器方法 ( ) 和类构造器( ) 并不是一回事

    • ( ) 方法不需要定义,而( ) 需要定义(不定义但是会有个默认为空的构造器方法)
    • 只有当代码中包含 static 变量时,才会执行 ( ) 方法,而( ) 所有类的字节码中都有


  • 在多线程时,初始化只执行一次,否则会被上锁

3.其他小结

  • 确定两个类是否相同
    • 包名、类名完全相同
    • 所用的类加载器也要相同
  • 类的主动使用和被动使用
    • 也就是是否有初始化过程,是否调用 clinit<>() 方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/338372.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

imgaug库图像增强指南(32):塑造【雪景】效果的视觉魔法

引言 在深度学习和计算机视觉的世界里&#xff0c;数据是模型训练的基石&#xff0c;其质量与数量直接影响着模型的性能。然而&#xff0c;获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此&#xff0c;数据增强技术应运而生&#xff0c;成为了解决这一问题的…

蓝桥杯练习题(十二)

&#x1f4d1;前言 本文主要是【算法】——蓝桥杯练习题&#xff08;十二&#xff09;的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他…

【蓝桥杯日记】复盘篇一:深入浅出顺序结构

&#x1f680;前言 本期是一篇关于顺序结构的题目的复盘,通过复盘基础知识&#xff0c;进而把基础知识学习牢固&#xff01;通过例题而进行复习基础知识。 &#x1f6a9;目录 前言 1.字符三角形 分析&#xff1a; 知识点&#xff1a; 代码如下 2. 字母转换 题目分析: 知…

加固密码安全:保护您的个人信息

一、引言 在数字化时代&#xff0c;密码安全是保护个人信息和数据的重要环节。然而&#xff0c;许多人在创建和管理密码时存在一些常见的安全漏洞&#xff0c;如使用弱密码、重复使用密码等。本文将详细介绍密码安全的重要性&#xff0c;并提供一些有效的方法和技巧&#xff0…

使用DALL-E 3模型模拟AI女友的一天 |【人人都是算法专家】

Rocky Ding 公众号&#xff1a;WeThinkIn 知乎&#xff1a;Rocky Ding 写在前面 【人人都是算法专家】栏目专注于分享AI行业中业务/竞赛/研究/产品维度的思考与感悟。欢迎大家一起交流学习&#x1f4aa; 大家好&#xff0c;我是Rocky。 我们都知道DALL-E 3是和Stable Diffusio…

Windows ssh登录eNSP交换机

目录 1. Cloud IO配置1.1 创建UDP端口1.2 创建本地连接1.3 端口映射设置 2. 交换机配置2.1 配置vlanif2.2 配置vty2.3 配置ssh用户2.4 配置aaa2.5 使用Xshell工具登录2.6 用户和密码2.7 登录成功 3. 使用cmd 登录报错提示3.1 手动指定加密算法&#xff0c;提示密码长度无效3.2 …

自定义注解与拦截器实现不规范sql拦截(拦截器实现篇)

最近考虑myBatis中sql语句使用规范的问题&#xff0c;如果漏下条件或者写一些不规范语句会对程序性能造成很大影响。最好的方法就是利用代码进行限制&#xff0c;通过拦截器进行sql格式的判断在自测环节就能找到问题。写了个简单情景下的demo&#xff0c;并通过idea插件来将myB…

Twisted Circuit洛谷绿题题解

Twisted Circuit 题面翻译 读入四个整数 0 0 0 或者 1 1 1&#xff0c;作为如图所示的电路图的输入。请输出按照电路图运算后的结果。 感谢PC_DOS 提供的翻译 题目描述 输入格式 The input consists of four lines, each line containing a single digit 0 or 1. 输出格…

编译和链接详解

文章目录 前言翻译环境和运行环境翻译环境和运行环境图解 翻译环境编译预处理&#xff08;预编译&#xff09;阶段编译汇编 链接 运行环境总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 在软件开发的世界中&#xff0c;编译和链接是构建程序的两个…

【GitHub项目推荐-开源的任务管理工具】【转载】

推荐一个开源的任务管理工具&#xff0c;该工具会提供各类文档协作功能、在线思维导图、在线流程图、项目管理、任务分发、即时 IM&#xff0c;文件管理等等。该开源项目使用到 Vue、Element-UI、ECharts 等技术栈。 开源地址&#xff1a;www.github.com/kuaifan/dootask 预览地…

5G_系统同步机制(八)

BBU和RRU的同步机制 为什么要做到系统同步 在TDD模式下工作时&#xff0c;为了避免相邻小区之间的干扰&#xff0c;近距离的所有gNB在任何时间点都必须具有相同的传输方向(DL或UL)。这样做的必要条件是在BTS之间同步SFN (System Frame number)和time Slot。此外&#xff0c;由…

meshgrid contour contourf

meshgrid contour contourf 参考video: https://www.bilibili.com/video/BV1qW411A775/?spm_id_from333.337.search-card.all.click&vd_sourced171c31a396363b8ea8c0e92a59cee6b 官方文档: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.contourf.html#ma…

嵌入式-C语言-江科大-数据类型宏定义#define关键字typedef结构体

这是C语言中高级相关知识&#xff0c;在单片机中实战的一些用法 参考C语言江科大视频的学习笔记&#xff0c;详细举例子并且完整记录up的想法&#xff0c;包括内容有c语言数据类型&宏定义#define&关键字typedef&结构体&预处理指令 文章目录 一:C语言数据类型二…

idea 折叠某段代码 这段特定某段代码

如何折叠IntelliJ IDEA代码片段_w3cschool ctrlALTT

HNU-数据挖掘-作业1

数据挖掘课程作业作业1 计科210X 甘晴void 202108010XXX 第一题 假设所分析的数据包括属性 age,它在数据元组中的值&#xff08;以递增序&#xff09;为13 ,15 ,16 ,16 ,19 ,20 ,20 ,21 ,22 ,22 ,25 ,25 ,25 ,25 ,30 ,33 ,33 ,35 ,35 ,35 ,35 ,36 ,40 ,45 ,46 ,52,70。 a.…

从零开始的OpenGL光栅化渲染器构建5-阴影

前言 阴影是光线被阻挡的结果&#xff1b;当一个光源的光线由于其他物体的阻挡不能够达到一个物体的表面的时候&#xff0c;那么这个物体就在阴影中了。阴影能够使场景看起来真实得多&#xff0c;并且可以让观察者获得物体之间的空间位置关系。 直接阴影 阴影映射(Shadow Ma…

C语言/c++指针详细讲解【超详细】【由浅入深】

指针用法简单介绍 指针&#xff0c;是内存单元的编号。 内存条分好多好多小单元&#xff0c;一个小单元有 8 位&#xff0c;可以存放 8 个 0 或 1&#xff1b;也就是说&#xff0c;内存的编号不是以位算的&#xff0c;而是以字节算的&#xff0c;不是一个 0 或 1 是一个编号&…

【题目】2023年国赛信息安全管理与评估正式赛任务书-模块3 CTF

全国职业院校技能大赛 高等职业教育组 信息安全管理与评估 任务书 模块三 网络安全渗透、理论技能与职业素养 竞赛相关资源资料可在文末关注公众号获得 比赛时间及注意事项 本阶段比赛时长为180分钟&#xff0c;时间为9:00-12:00。 【注意事项】 &#xff08;1&#xf…

做一个简单的倒计时

<div>距离过年还有:<span></span></div><script>let div document.querySelector("div");let span document.querySelector("span");// 获取未来时间戳let future new Date("2024-2-10 00:00:00");// 获取当下…

深度解析Python关键字:掌握核心语法的基石(新版本35+4)

目录 关键字 keyword 关键字列表 kwlist softkwlist 关键字分类 数据类型 True、False None 运算类型 and、or、not in is 模块导入 import 辅助关键字 from、as 上下文管理 with 占位语句 pass 流程控制 if、elif、else for while break、continue…