JVM 运行流程

JVM Java 运行的基础,也是实现一次编译到处执行的关键,那么 JVM 是如何执行的呢?

JVM 执行流程


程序在执行之前先要把java代码转换成字节码(class 文件) JVM 首先需要把字节码通过一定的
方式 类加载器(ClassLoader)   把文件加载到内存中  运行时数据区(Runtime Data Area) ,而字节码文件是 JVM 的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器 执行引擎(Execution Engine) 字节码翻译 成底层系统指令再交由 CPU 去执行,而这个过程中需要调用其他语言的接口 本地库接口(Native Interface) 来实现整个程序的功能,这就是这 4 个主要组成部分的职责与功能。
总结来看, JVM 主要通过分为以下 4 个部分,来执行 Java 程序的,它们分别是:
1. 类加载器(ClassLoader
2. 运行时数据区(Runtime Data Area
3. 执行引擎(Execution Engine
4. 本地库接口(Native Interface

JVM 运行时数据区 


JVM 运行时数据区域也叫内存布局,但需要注意的是它和 Java 内存模型( (Java Memory Model ,简称JMM)完全不同,属于完全不同的两个概念,它由以下 5 大部分组成:

2.1 堆(线程共享)

堆的作用:程序中创建的所有对象都在保存在堆中。
堆里面分为两个区域:新生代和老生代,新生代放新建的对象,当经过一定 GC 次数之后还存活的对象会放入老生代。新生代还有 3 个区域:一个 Endn + 两个 Survivor S0/S1 )。
垃圾回收的时候会将 Endn 中存活的对象放到一个未使用的 Survivor 中,并把当前的 Endn 和正在使用的 Survivor 清楚掉。

2.2 Java虚拟机栈(线程私有)

Java 虚拟机栈的作用: Java 虚拟机栈的生命周期和线程相同, Java 虚拟机栈描述的是 Java 方法执行的 内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame )用于存储局部变量表、操作数 栈、动态链接、方法出口等信息。咱们常说的堆内存、栈内存中,栈内存指的就是虚拟机栈。
Java 虚拟机栈中包含了以下 4 部分:
  1. 局部变量表: 存放了编译器可知的各种基本数据类型(8大基本数据类型)、对象引用。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在执行期间不会改变局部变量表大小。简单来说就是存放方法参数和局部变量。
  • 操作栈:某些字节码指令把值压入操作数栈,其余指令将操作数取出栈。使用他们后再把结果压入栈。比如:执行复制、交换、求和等操作。
  1. 动态链接:指向运行时常量池的方法引用。
  2. 方法返回地址:PC 寄存器的地址。

什么是线程私有 ?
由于 JVM 的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现,因此在任何一个确定的时
刻,一个处理器 ( 多核处理器则指的是一个内核 ) 都只会执行一条线程中的指令。因此为了切换线程后能
恢复到正确的执行位置,每条线程都需要独立的程序计数器,各条线程之间计数器互不影响,独立存
储。我们就把类似这类区域称之为 " 线程私有 " 的内存

2.3 本地方法栈(线程私有)

本地方法栈和虚拟机栈类似,只不过 Java 虚拟机栈是给 JVM 使用的,而本地方法栈是给本地方法使用的。

2.4 程序计数器(线程私有)

程序计数器的作用:用来记录当前线程执行的行号的。
程序计数器是一块比较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。
如果当前线程正在执行的是一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;
如果正在执行的是一个 Native 方法,这个计数器值为空。
程序计数器内存区域是唯一一个在 JVM 规范中没有规定任何 OOM 情况的区域!

2.5 方法区(线程共享)

方法区的作用:用来存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
的。
在《 Java 虚拟机规范中》把此区域称之为 方法区 ,而在 HotSpot 虚拟机的实现中,在 JDK 7 时此区域叫做永久代(PermGen ), JDK 8 中叫做元空间( Metaspace )。
PS :永久代( PermGen )和元空间( Metaspace )是 HotSpot 中对《 Java 虚拟机规范》中方法
区的实现,它们三者之间的关系就好比,对于一辆汽车来说它定义了一个部分叫做 动能提供装
,但对于不同的汽车有不同的实现技术,比如对于燃油车来说,它的 动能提供装置 的实现技
术就是汽油发动机(简称发动机),而对于电动汽车来说,它的 动能提供装置 的实现就是电动
发动机(简称电机),发动机和电机就相当于永久代和元空间一样,它是对于 制动器 也就是方
法区定义的实现。
1. 对于 HotSpot 来说, JDK 8 元空间的内存属于本地内存,这样元空间的大小就不在受 JVM 最大内
存的参数影响了,而是与本地内存的大小有关。
2. JDK 8 中将字符串常量池移动到了堆中。
运行时常量池
运行时常量池是方法区的一部分,存放字面量与符号引用。
字面量 : 字符串 (JDK 8 移动到堆中 ) final常量、 基本类型的包装类

java中基本类型的包装类的大部分都实现了常量池技术,即Byte,Short,Integer,Long,Character,Boolean。这5种包装类默认创建了数值[-128,127]的相应类型的缓存数据,但是超出此范围仍然会去创建新的对象。

两种浮点数类型的包装类Float,Double并没有实现常量池技术。

符号引用 : 类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符。
  • 类和结构的完全限定名 :包括包名和类/接口名。
  • 字段的名称和描述符:是一个简短的字符串,描述了字段的类型。
  • 方法的名称和描述符: 是一个简短的字符串,描述了方法的返回类型和参数类型。

JVM 类加载 


类加载过程
从上面的图片我们可以看出整个 JVM 执行的流程中,和程序员关系最密切的就是类加载的过程了,所以
接下来我们来看下类加载的执行流程。
对于一个类来说,它的生命周期是这样的
其中前 5 步是固定的顺序并且也是类加载的过程,其中中间的 3 步我们都属于连接,所以对于类加载来
说总共分为以下几个步骤:
1. 加载
2. 连接
        1. 验证
        2. 准备
        3. 解析
3. 初始化
下面我们分别来看每个步骤的具体执行内容。

1) 加载

加载即Java 类的字节码文件加载到机器内存中,并在内存中构建出 Java 类的原型——类模板对象。所谓类模板对象,其实就是 Java 类在 JVM 内存中的一个快照,JVM 将从字节码文件中解析出的常量池、类字段、类方法等信息存储到模板中,这样 JVM 在运行期便能通过类模板而获取 Java 类中的任意信息,能够对 Java 类的成员变量进行遍历,也能进行 Java 方法的调用。

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

  • 通过一个类的全限定名来获取定义此类的二进制字节流
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

2) 验证

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

3) 准备

准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值 的阶段。
比如此时有这样一行代码:
public static int value = 123;
它是初始化 value int 值为 0 ,而非 123

4) 解析

解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程。

5) 初始化

初始化阶段,Java 虚拟机真正开始执行类中编写的 Java 程序代码,将主导权移交给应用程序。初始化阶段就是执行类构造器方法的过程。

双亲委派模型

什么是双亲委派模型?
如果一个类加载器收到了类加载的请求,(加载1)时)它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最 终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无 法完成这个加载请求(它的搜索范围中没有找到所需的类) 时,子加载器才会尝试自己去完成加载。
  • 启动类加载器:加载 JDK lib 目录中 Java 的核心类库,即$JAVA_HOME/lib目录。 扩展类加载器。加载 lib/ext 目录下的类。
  • 应用程序类加载器:加载我们写的应用程序。
  • 自定义类加载器:根据自己的需求定制类加载器。
双亲委派模型的优点
1. 避免重复加载类:比如 A 类和 B 类都有一个父类 C 类,那么当 A 启动时就会将 C 类加载起来,那么在 B 类进行加载时就不需要在重复加载 C 类了。
2. 安全性:使用双亲委派模型也可以保证了 Java 的核心 API 不被篡改,如果没有使用双亲委派模
型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object
类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类,而有些 Object 类又是用户
自己提供的因此安全性就不能得到保证了。

 

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

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

相关文章

独立游戏之路 -- 上架TapTap步骤和注意事项

个人开发者游戏上架TapTap上架步骤和注意事项 一、TapTap 介绍二、独立游戏上架 TapTap 的步骤2.1 创建游戏2.2 提交游戏审核2.3 TapTap 平台上发布。 三、注意事项3.1 关于备案3.2 遵守 TapTap 的规定3.3 保证游戏质量 四、常见问题4.1 隐私政策问题4.2 先发布还是先优化&…

Mybatis02-CRUD操作及配置解析

1、CRUD 1.namespace namespace中的包名要和Dao/Mapper 接口的包名一致! 1个Dao接口类对应1个mapper,也对应1个namespace, 1个Dao接口中的方法对应1个namespace中一个SQL语句 2.CRUD id:对应的namespace接口中的方法名resul…

【读书笔记】曼陀罗思考法

目录 1 起源2 路径示例——人生规划设计 3 分类3.1 扩展型“扩展型”曼陀罗——使用方法 3.2 围绕型 4 注意事项 1 起源 曼陀罗在梵文中意味着“圣地”,象征着宇宙的秩序和内心的神圣结构。 “曼陀罗思考法”,是由日本学者今泉浩晃发明的方法&#xff…

从零开始实现自己的串口调试助手(6) -换行问题

解决接收的自动换行 自动换行原因 --> 我们以append发送 会自动换行 换个api 即可 --> 我们换成 insertPlainText 添加自动换行 实现添加新行 修改的函数代码: on_btnSendContext_clicked void Widget::on_btnSendContext_clicked() {// const char * sendData ui->…

C#WPF数字大屏项目实战10--不良指标分页

1、区域划分 2、区域布局 3、视图模型 4、控件绑定 5、运行效果 走过路过,不要错过,欢迎点赞,收藏,转载,复制,抄袭,留言,动动你的金手指,财务自由

java常见api :Math System

一. Math类 1.定义在那个包 java.lang包下 2.作用 (1)是一个帮助我们用于进行数学计算的工具类 (2)私有化构造方法,所有的方法都是静态的 3.常用的方法 (1)获取绝对值 System.out.println(Math.abs(-88)); 取值范围: -2147483648到21…

工信部《工业和信息化领域数据安全风险评估实施细则(试行)》实行,行云管家数据产品助力企业数据安全

2024年6月1日,工信部颁布的《工业和信息化领域数据安全风险评估实施细则(试行)》(以下简称《细则》)开始实行,旨在引导工业和信息化领域数据处理者规范开展数据安全风险评估工作,提升数据安全管…

精打细算:可燃气体报警器检验收费的合理规划与管理

随着工业化的快速发展,可燃气体报警器已经成为各类工业场所不可或缺的安全设备。 它的主要功能是在可燃气体浓度超标时发出警报,有效预防和减少火灾、爆炸等安全事故的发生。 然而,为了确保报警器能够持续、准确地发挥作用,定期…

【Python】 Python单元测试入门:运行典型的测试目录结构

基本原理 单元测试是软件开发中不可或缺的一部分,它帮助开发者确保每个单元(通常是函数或类方法)在修改后仍然按预期工作。Python 的 unittest 模块提供了一套丰富的工具来帮助开发者编写和运行单元测试。 在 Python 项目中,一个…

godot的安装和使用 1

今天是第一节,因此呢先做godot的安装,其实很简单 godot官网:https://godotengine.org/ 进入官网, 安装好之后呢,会有两个文件 打开第一个就是可视化界面的,进入后是这个样子 说明安装成功了

try…except…finally语句

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 完整的异常处理语句应该包含finally代码块,通常情况下,无论程序中有无异常产生,finally代码块中的代码都会被执行…

实战:一款唯美的个人主页-home2.0-2024.6.4(测试成功)

目录 文章目录 目录实验软件前提条件效果说明1、背景2、配置1、克隆代码库2、配置并构建镜像3、部署测试方案1:从docker容器拷贝生成的静态文件放到网站/目录方案2:启动容器,nginx里配置反向代理(推荐) 4、访问 3、总结…

JSON 数据格式化方法

文章目录 数据介绍IDE 或脚本格式化在线工具网址总结 数据介绍 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它基于JavaScript 编程语言的一个子集。尽管它起源于 JavaScript,但 JSON 已经成为了一个完全独立于…

杨校老师项目之SpringBoot整合Vue与微信小程序的外卖订餐系统

1.获取代码: 有偿获取:mryang511688 2.技术栈 SpringBoot MySQL mybatis Redis 微信小程序 摘 要 随着国内外卖行业的蓬勃发展,外卖平台间的竞争影响了许多餐饮企业。许多餐饮企业面临着第三方外卖平台抽佣高、营销策略受限等问题&am…

【Game】Powerful——Collection of Mystical Treasures(2)

参考来自: 非凡日常15|秘宝集解读第一版,玩法触发猜想! 关键词22|“探秘”、“秘宝集”,完整版 关键词22|“探秘”、“秘宝” 《神武4》百趣集探秘攻略 秘宝宝藏触发条件 文章目录 规则普通秘宝特殊秘宝新增秘宝 规则 基础次…

SmartEDA:电子设计新手进阶宝典,轻松开启创意之旅

在科技日新月异的今天,电子设计已成为众多创新者和工程师们展示才华的重要舞台。然而,对于初学者来说,电子设计的世界往往显得既神秘又复杂。幸运的是,有了SmartEDA这样的强大工具,新手也能轻松入门,逐步精…

i.MX8MP平台开发分享(MU功能介绍篇)

消息传递单元(MU)模块通过 MU 接口传递消息(如数据、状态和控制),使 SoC 中的两个处理器能够进行通信和协调。MU 还能让一个处理器使用中断向另一个处理器发出信号。 由于 MU 管理处理器之间的信息传递,因…

spring boot 2.1 集成activiti 6.0.0和activiti-modeler 5.23.0可视化编辑器(随记)

先上pom&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.or…

【WRF理论第二期】模型目录介绍

WRF理论第二期&#xff1a;模型目录介绍 1 WRF主目录2 WPS主目录3 编译后的可执行文件4 运行目录参考 了解 WRF 模型的目录结构有助于有效地管理和操作模型&#xff0c;从而确保模拟和分析工作的顺利进行。以下分解介绍WRF主目录、WPS主目录等。 Github-wrf-model/WRF 1 WRF…

小程序CI/CD之自动化打包预览并钉钉通知发布进程

小程序打包方式分为两种&#xff1a;手动打包、自动打包 那如何实现 自动打包 呐&#xff1f;我们今天就来聊一聊&#xff01; 首先&#xff0c;很重要&#xff0c;看 官方文档 这里提到今天我们要聊的“主角” miniprogram-ci miniprogram-ci 是从微信开发者工具中抽离的关于…