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 类又是用户
自己提供的因此安全性就不能得到保证了。

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

文件怎么加密?文件加密软件哪个好用?

在数字化生活和工作中,文件安全已成为不容忽视的话题。 为了保护个人隐私和企业敏感数据不被非法访问或泄露,文件加密成为了不可或缺的手段。 本文将介绍文件加密的基本概念、加密方法以及推荐几款好用的文件加密软件,帮助您为重要文件穿上“…

捋一捋C++中的逻辑运算(一)——表达式逻辑运算

注意,今天要谈的逻辑运算是C语言编程中的“与或非”逻辑运算,不是数学集合中的“交并补”逻辑运算。而编程中的逻辑运算又包括表达式逻辑运算和位逻辑运算,本章介绍表达式逻辑运算,下一章介绍位逻辑运算。 目录 一、几个基本的概…

视频号上怎么卖货?需要直播,还有粉丝吗?一篇文章带你了解!

大家好,我是电商糖果 关于在视频号上卖货,这是大家最常提起的话题。 大家之所以对视频号卖货感兴趣,主要原因还是抖音卖货火起来了。 而视频号是和抖音处于同一个赛道,这两年也在往电商方向发力。 所以大家对视频号推出电商平…

Window11端口开放防火墙

(1)打开控制面板,进入【控制面板\系统和安全\Windows Defender 防火墙】 (2)点击左侧菜单【高级设置】,进入防火墙设置页面 (3)根据需要选择【入站规则】或者【出站规则】&#xff…

ubtun三节点安装k8s

文章目录 修改Ubuntu配置关闭swap:关闭防火墙 安装docker 修改Ubuntu配置 关闭swap: vim /etc/fstab /dev/disk/by-uuid/a1ce2ecf-91f4-4f53-9984-b2af1e9713c5 /boot ext4 defaults 0 1 /swap.img none swap sw 0 0修改/dev/dis…

nestjs 全栈进阶--拦截器

视频教程 23_nestjs中的拦截器_哔哩哔哩_bilibili 1. rxjs 介绍 RxJS(Reactive Extensions for JavaScript)是一款专为JavaScript和TypeScript设计的响应式编程库,它遵循ReactiveX规范,提供了一套强大的工具和API,用…

Mac 使用Docker安装Elasticsearch、Kibana

安装ElasticSearch 通过docker安装es docker pull elasticsearch:8.6.2 在本地创建elasticsearch.yml文件 mkdir /Users/ky/Documents/learn/es/elasticsearch.yml 编辑yml文件内容 http: host: 0.0.0.0 xpack.security.enabled: false xpack.security.enrollment.enabled: t…

Scala 练习一 将Mysql表数据导入HBase

Scala 练习一 将Mysql表数据导入HBase 续第一篇:Java代码将Mysql表数据导入HBase表 源码仓库地址:https://gitee.com/leaf-domain/data-to-hbase 一、整体介绍 HBase特质 连接HBase, 创建HBase执行对象 初始化配置信息:多条(hbase.zookeeper.…

ARM学习(28)NXP 双coreMCU IMX1160学习

笔者最近接触到一块IMXRT1160的双core板子,特依次来记录学习一下 1、IMXRT1160 板子介绍 介绍一下NXP的Demo板子,是一个双core的板子,Cortex-M7和Cortex-M4,总计1MB的RAM空间,256KB的ROM空间,提供了丰富的…

Window10磁盘的分盘和合并

注意: 当我们c盘不够大需要扩大磁盘空间时,当c盘后面没有未划分的磁盘时候,我们是无法进行扩充c盘的,此时,我们可以先删除后面一个磁盘,再进行扩大。 如下:c盘后没有未分配的空间,…

【项目管理常见问题大揭秘】每个管理者都要Get的「五维思维」~

走上管理岗☸要懂得五维思维 💼自我管理——做自己的CEO 严于律己:严格要求自己,注重个人品牌建设 宽以待人:接纳不同观点,提升团队凝聚力 尊重事实:鼓励团队成员发挥优势,避免负面评价 坚守诚…

求助:西莫电子期刊 交流互助 传递

点击上方 “机械电气电机杂谈 ” → 点击右上角“...” → 点选“设为星标 ★”,为加上机械电气电机杂谈星标,以后找夏老师就方便啦!你的星标就是我更新动力,星标越多,更新越快,干货越多! 关注…

Java面经——SpringCloud微服务

SpringCloud SpringCloud的五大组件 注册中心网关远程调用负载均衡熔断降级 谈谈你对SpringCloud的理解 SpringCloud是为了解决微服务架构中出现的一系列服务治理难题的而提出的一套规范,统一了标准。降低了微服务架构的开发难度。有了 Spring Cloud 这样的技术生…

【android 9】【input】【8.发送按键事件2——InputDispatcher线程】

系列文章目录 本人系列文章-CSDN博客 目录 系列文章目录 1.简介 1.1流程介绍 1.2 时序图 2.普通按键消息发送部分源码分析(按键按下事件) 2.1 开机后分发线程阻塞的地方 2.2 InputDispatcher::dispatchOnceInnerLocked 2.3 InputDispatcher::disp…

使用C语言实现贪吃蛇(超详细)

目录 实现贪吃蛇我们要知道哪些? Easyx图形库 Easyx的安装 游戏思路 游戏实现 头文件的使用 ​编辑和食物以及控制方向的初始化 对于坐标的实现: 食物颜色的实现: 游戏数据的初始化 加载音乐 图形窗口的设置: 蛇身节数…

【动手学深度学习】多层感知机之暂退法问题研究详情

目录 🌊问题研究1 🌞问题研究2 🌲问题研究3 🌍问题研究4 🌳问题研究5 🌌问题研究6 🌊问题研究1 如果更改第一层和第二层的暂退法概率,会发生什么情况?具体地说&am…

深入理解指针(4)--新手小白都能明白的指针解析

深入理解指针(4)–新手小白都能明白的指针解析 文章目录 深入理解指针(4)--新手小白都能明白的指针解析1. 回调函数2. qsort使用举例2.1 冒泡排序2.2 qsort函数介绍2.3 用冒泡排序实现qsort 结语 1. 回调函数 回调函数就是⼀个通过函数指针调用的函数 如果我们把函数的指针&a…

玩转微服务-GateWay

目录 一. 背景二. API网关1. 概念2. API网关定义3. API网关的四大职能4. API网关分类5. 开源API网关介绍6. 开源网关的选择 三. Spring Cloud Gateway1. 文档地址2. 三个核心概念3. 工作流程4. 运行原理4.1 路由原理4.2 RouteLocator 5. Predicate 断言6. 过滤器 Filter6.1. 过…

[图解]建模相关的基础知识-02

1 00:00:01,530 --> 00:00:05,200 第2个概念,谓词,Predicate 2 00:00:07,530 --> 00:00:10,800 或者叫断言,翻译各种各样都有 3 00:00:12,830 --> 00:00:15,050 实际上就是前面命题 4 00:00:15,060 --> 00:00:16,610 相当于常…

记录Nuxt 3 官网项目的一次部署

本来以为就是一次简单的部署,之前也是部署过几次nuxt项目了,所以,并没有要记录的想法。但是过程出现了很多问题,最后考虑还是写下来吧。留个记录(完整的配置部署过程) 这里我将要说明两种部署方式以供选择&…