深入理解JVM - 虚拟机字节码执行引擎

【AI落地】AI生成测试用例,claude or gpt?(提效至少 50%) gpt生成测试用例?当然好使啦,用好了提效50%+,用不好就让他变好! 阅读详情

执行引擎是Java虚拟机最核心的组成部分之一,输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果。

1、栈帧


栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈的栈元素。栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每一个方法从调用开始至执行完成的过程,都对应了一个栈帧在虚拟机栈里面从入栈到出栈的过程。

在编译程序代码的时候,栈帧中需要多大的局部变量表,多深的操作数栈都已经完全确定了,并且写入到方法表的Code属性中,因此一个栈帧需要分配多少内存,不会收到程序运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。对于执行引擎来说,在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧,与这个栈帧相关联的方法称为当前方法。执行引擎的所有字节码指令都只针对当前栈帧进行操作。

1.1、局部变量表

局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。在Java程序编译为Class文件时,就在方法的Code属性的max_locals数据项中确定了该方法所需要分配的局部变量表的最大容量。

局部变量表的容量以变量槽(slot)为最小单位。一个Slot可以存放一个32位以内的数据类型。对于64位的数据类型,虚拟机会以高位对齐的方式为其分配两个连续的Slot空间,在Java语言中明确的64位数据类型只有long和double两种。值得一提的是,这里把long和double数据类型分割存储的做法与“long和double的非原子性协定”中把一次long和double数据类型读写分割成两次32位读写的做法有些类似。不过,由于局部变量表建立在线程的堆栈上,是线程私有的数据,无论读写两个连续的Slot是否为原子操作,都不会引起数据安全问题。

在方法执行时,虚拟机是使用局部变量表完成参数值到参数变量列表的传递过程的,如果执行的是实例方法,那局部变量表中的第0位索引的Slot默认是用于传递方法所属对象实例的引用,在方法中可以通过关键字this来访问到这个隐藏的参数。其余的参数则按照参数表顺序排列,占用从1开始的局部变量Slot,参数分配完毕之后,再根据方法体内部定义的变量顺序和作用域分配其余的Slot。

局部变量表中的Slot是可以重用的,方法体中定义的变量其作用域并不一定会覆盖整个方法体,如果当前字节码PC计数器的值已经超出了某个变量的作用域,那这个变量对用的Slot就可以交给其他变量使用。这样的设计除了可以节省栈帧空间以外,还会伴随着一些额外的副作用,比如直接影响系统的垃圾收集行为。

public static void main(String[] args) {
        byte[] placeHolder = new byte[64*1024 * 1024];
        System.gc();
    }
    [GC 66846->65824K(125632K),0.0032678 secs]
    [Full GC 65824->65746K(125632K),0.0064131 secs]
可以看到运行System.gc()之后并没有回收64M的内存。没有回收placeHolder所占的内存能说的过去,因为在执行System.gc()的时候,变量placeHolder还处于作用域之内,虚拟机自然不敢回收placeHolder的内存。

  public static void main(String[] args) {
        {
            byte[] placeHolder = new byte[64*1024 * 1024];
        }
        System.gc();
    }
    [GC 66846->65824K(125632K),0.0032678 secs]
    [Full GC 65824->65746K(125632K),0.0064131 secs]
加上花括号之后,placeHolder的作用域被限制在了花括号之内,从代码逻辑上讲,在执行System.gc()的时候,placeHolder已经不能再访问了,但是运行之后会发现64M内存没有被回收。

public static void main(String[] args) {
        {
            byte[] placeHolder = new byte[1024 * 1024];
        }
        int a = 0;
        System.gc();
    }
    [GC 66401->65778K(125632K),0.0035471 secs]
    [Full GC 65824->218K(125632K),0.00140596secs]
运行之后,可以发现64M的内存被回收了。placeHolder被回收的根本原因是:局部变量表中的Slot是否还存在有关于placeHolder数组对象的引用。第一次修改中,代码虽然已经离开了placeHolder的作用域。但在此之后,没有任何对局部变量表的读写操作,placeHolder原本所占用的Slot还没有被其他变量复用,所以作为GC Root一部分的局部变量表仍然保持着对它的关联。这种关联没有被及时的打断,在绝大多数情况下影响很轻微。但如果遇到了方法,其后面的代码有一些耗时很长的操作,而前面又定义了占用了大量内存、实际上已经不再使用的变量,手动将其置成null值便不见得是一个绝对无意义的操作。
注意:虽然在某些特殊的情况下,赋null值确实是有用的,但是不应当对赋null值的操作有过多的依赖,更没有必要把它当作一个普遍的编码规则来推广。

关于局部变量表,还有一点需要知道,就是局部变量不像前面介绍的类变量那样存在“准备阶段”。我们已经知道类变量有两次赋初始化值的过程,一次是在准备阶段,赋予系统初始值;另一次在初始化阶段,赋予程序员定义的初始值。因此,即使在初始化阶段程序员没有为类变量赋值也没有关系,类变量仍然具有一个确定的初始值,但局部变量就不一样了,如果一个局部变量没有赋初始值是不能使用的,不要认为Java中任何情况下都存在诸如整型变量默认值为0,布尔值变量默认为false等这样的默认值。

1.2、操作数栈

操作数栈也称为操作栈,它是一个后入先出栈。同局部变量表一样,操作数栈的最大深度也在编译的时候写入Code属性的max_stacks数据项中。操作数栈的每一个元素可以使任意的Java数据类型,包括long和double。32位数据类型所占的栈容量是1,而64位数据类型所占的栈容量为2。在方法执行过程的任何时候,操作数栈的深度都不会超过在max_stacks数据项中设定的最大值。

当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈和入栈的操作。举个栗子,整数加法的字节码指令iadd在运行的时候操作数栈中最接近栈顶的两个元素已经存入了两个int型的整数值,当执行这个指令时,会将这两个int值出栈并相加,然后将相加的结果入栈。

Java虚拟机的解释执行引擎称为“基于栈的执行引擎”,其中所指的“栈”就是操作数栈。

1.3、动态连接

每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。我们知道Class文件的常量池中存在了大量的符号引用,字节码的方法调用指令就以常量池中指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或者第一次使用的时候就转化为直接引用,这种转化称为静态解析。另外一部分将每一次运行期间转化为直接引用,这部分称为动态连接。

1.4、方法返回地址

当一个方法开始执行后,只有两种方式可以退出这个方法:1、执行引擎遇到任意一个方法返回的字节码指令,这时候可能会有返回值传递给上层的方法调用者。这种退出方法的方式称为正常完成出口。2、在方法的执行过程中遇到了异常,并且这个异常没有在方法体内得到处理,无论是虚拟机内部产生的异常还是代码中athrow字节码指令产生的异常,只要在本方法的异常表中没有搜索到匹配的异常处理器,就会导致方法退出。这种退出方法的方式被称为异常完成出口。一个方法使用异常完成出口的方式退出,是不会给上层调用者产生任何返回值的。

方法退出的过程实际上等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值(如果有的话)压入调用者栈帧的操作数栈中,调整PC计数器的值以便指向方法调用指令后面的一条指令等。

--------------------------------方法调用、基于栈的解释器执行过程----------------------------------------

ABAP Channels 实战:在 ABAP 7.40 中用 WebSocket 打造实时双向通信 本文详细介绍了SAP ABAP 7.40引入的ABAP Channels通信框架,包含AMC(ABAP Messaging Channels)和APC(ABAP Push Channels)两部分。AMC作为应用服务器内部的消息总线,支持发布/订阅模式,可实现跨会话实时通信;APC基于WebSocket协议,用于浏览器等客户端与ABAP服务器的双向实时交互。文章通过一个乒乓球游戏案例展示了ABAP Channels的实时协作能力,并详细解析了AMC的配置方法、消息发送与接收的代码实现,帮助开发者理解如何利用 阅读详情

相关推荐

matlab球面投影(二)

matlab球面投影,想做一个全景相机,不知道,要做成啥样,于是在MATLAB先仿真一下,看下是个啥样子 百度别人做的,复制下面的代码到MATLAB的命令串口下,,网上找了张全景图,可以是bmp,jpg,改程序就可以了 回车运行就可以看到结果。 复制下面代码时,下面的中文注释记得删除,MATLAB是会报错的, close all; clear all; clc [x,y,z]=sphere(50); A=imread('a.JPG'); //名字是自己命名的,记得改 B=warp(x,y,-z,

rjszcb的博客 3161

JMM(JVM内存模型)

Java通过多线程机制实现多任务并行处理。 所有线程共享JVM内存(main memory),同时线程又有自己的工作内存。 当线程与主存进行交互时,数据从主存复制到工作内存中,由线程进行处理。 JVM的逻辑内存模型中,包含如下几个部分: 1)程序计数器 2)虚拟机栈 3)本地方法栈 4)Java堆 5)方法区 一、程序计数器 程序计数器是一块较小的内存空间。它可以被理解为是当前正在执行的...

look4liming的专栏 1090

高分系列卫星轨道、传感器参数等信息

遥感卫星数据简介-高分系列

中遥科 3309

JVM —— JMM 简述

JDK 1.8 内存模型 程序计数器 一块比较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。 Java虚拟机栈 每个方法执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中入栈和出栈的过程。 之前我们一直讲的栈区域实际上就是此处的虚拟机栈,再详细一点,是虚拟机栈中的局部变量表部分。 此区域一共会产生以下两种异常: 1. 如果线程请求的栈深度大于虚拟机所允许的深度(-Xss设置栈容量.

qq_45914985的博客 278

SAP Script表单开发中ABAP preform方法的实战应用与调试技巧

本文深入探讨了在SAP Script表单开发中调用ABAP程序(preform方法)的实战应用与调试技巧。通过一个获取供应商版本名称的实例,详细讲解了如何在SE71中嵌入PERFORM指令、编写ABAP子程序进行数据查询与处理,并重点介绍了使用SAP Script Debugger进行高效调试的方法,帮助开发者灵活扩展表单功能,实现复杂业务逻辑。

o0p1q2r3的博客 551

Apollo学习笔记(4)坐标系

百度Apollo项目用到了多种坐标系,其中帮助文档提及的坐标系包括: 全球地理坐标系(The Global Geographic coordinate system ) 局部坐标系—东-北-天坐标(The Local Frame – East-North-Up,ENU) 车身坐标系—右-前-天坐标(The Vehicle Frame —Right-Forward-Up,RFU) 车身坐标系—前-左-天坐标(The Vehicle Frame —Front-Left-Up,FLU) 还有一种Frenet坐标

qq_24649627的博客 5798

深入理解JVM - 编译期/运行期优化

----------------------------编译期优化-------------------------------------- 1、概述(编译期) Java语言的“编译期”其实是一段“不确定”的操作过程,因为它可能是指一个前端编译器(Javac编译器)把Java文件转变为class文件的过程;也可能是指虚拟机的后端运行期编译器(JIT编译器)把字节码转变为机器码的过程;还可能是

json_it的博客 1543

Vue3实战:从零构建ElementPlus后台管理系统全流程

本文详细介绍了从零开始使用Vue3和ElementPlus构建后台管理系统的全流程。内容涵盖环境准备、项目初始化、Vite配置、SCSS样式体系搭建、ElementPlus组件库引入与配置,以及封装可复用的SvgIcon组件进行图标管理,旨在帮助开发者快速搭建现代化、可维护的中后台应用。

weixin_29011239的博客 160

JVM 具体是怎样运行 Java 字节码的

文章目录为什么 Java 要在虚拟机里运行?Java 虚拟机具体是怎样运行 Java 字节码的? Java 代码有很多种不同的运行方式,可以在开发工具种运行;可以双击执行 jar 文件运行;可以在命令行种运行;甚至可以在网页种运行,这些都离不开 JRE,也就是 Java运行环境。(包含 Java 程序的必须组件,即 Java 虚拟机以及 Java 核心类库等) 为什么 Java 要在虚拟机里运行? Java 的语法很复杂,抽象程度高,直接在硬件上运行这种复杂的程序并不惜那是,所以在在运行之前需要进行转换。

@另维 1639

智能挂锁软件需求规格说明书(SRS)

智能挂锁系统SmartPadlockV1.0是一款融合蓝牙通信、指纹识别和远程控制技术的便携式安防设备。系统由设备端、移动App和云平台三部分组成,支持蓝牙配对(10米内)、指纹识别、OTP一次性密码等多种开锁方式,响应时间<1.5秒。产品采用SM2/SM4加密技术保障安全,日均20次使用下续航达180天,兼容iOS13+/Android8.0+系统。功能包括设备绑定、远程授权、开锁记录查询和OTA固件升级,符合个人信息保护法规要求,适用于仓储、快递柜等多场景应用。

moton2017的博客 2111

具身智能:原理、算法与系统 第1章 具身智能的本质与范畴

从学术定义的角度,具身智能可被界定为"与物理环境进行有目的的能量与信息交换"的智能形式。这一定义揭示了具身智能的两个本质维度:信息处理维度与能量交互维度。与传统人工智能系统仅在信息空间操作不同,具身智能系统必须同时处理信息流与能量流,在物理约束下实现感知、认知与行动的统一。具身智能体具有三个核心构成要素:物理身体(Physical Body)、感知系统(Sensory System)与效应器(Effectors)。这三者共同构成了感知与行动的基础,使智能体能够通过物理交互而非纯粹符号操作来理解世界。

VectorShift的博客 270

JMM(jvm运行时数据区)

u011264824的专栏 290

Airtest进阶使用篇-提高脚本稳定性+批量运行脚本

Airtest进阶篇,主要分享如何提高脚本稳定性+如何批量运行脚本生成测试报告!

程序员小杨哥的博客 2569

深入理解JVM之虚拟机字节码执行引擎

读了深入理解JVM之虚拟机字节码执行引擎这一章,

Sweet Baby,甜宝 1680

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

深入理解JVM 第八章 虚拟机字节码执行引擎

深入理解JVM 第八章 虚拟机字节码执行引擎1 概述2 运行时栈帧结构2.1 局部变量表2.2 操作数栈2.3 动态连接2.4 方法返回地址 1 概述 在Java虚拟机规范中规定了虚拟机字节码执行引擎的概念模型,这个概念模型成为各种虚拟机执行引擎的统一外观(Facade)。在不同的虚拟机实现里面,执行引擎在执行Java代码的时候可能由解释执行(通过解释器执行)和编译执行(通过即时编译器产生本地代码执行)两种选择,也可能两者兼备,甚至还可能包含几个不同急别的编译器执行引擎。但从外观上看起来,所有的Java虚拟

Seven_Year1的博客 647

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

深入理解JVM虚拟机5:虚拟机字节码执行引擎

1 概述 执行引擎是java虚拟机最核心的组成部件之一。虚拟机的执行引擎由自己实现,所以可以自行定制指令集与执行引擎的结构体系,并且能够执行那些不被硬件直接支持的指令集格式。 所有的Java虚拟机的执行引擎都是一致的:输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果。本节将主要从概念模型的角度来讲解虚拟机的方法调用和字节码执行。 2 运行时栈帧结构 栈帧(Stack Frame)是用于支持虚拟机方法调用和方法执行的数据结构,它是虚拟机运行时数据区中虚拟机栈(Virtual Ma.

wr_java的博客 191

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

深入理解JVM:虚拟机字节码执行引擎

一、运行时栈结构 栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构。 栈帧包括:局部变量表、操作数栈、动态连接、方法的返回地址 和一些额外的附加信息。 执行引擎运行的所有字节码指令只针对当前栈帧进行操作。需要注意的是一个栈中能容纳的栈帧是受限,过深的方法调用可能会导致StackOverFlowError,当然,我们可以认为设置栈的大小。其模型示意图大体如下: 执行引擎的所有字节码...

Zystem 426

深入理解Java虚拟机:Jvm总结-虚拟机字节码执行引擎

不受物理条件制约地定制指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式。输入的是字节码二进制流,处理过程是字节码解析执行的等效过程,输出的是执行结果。

Oceáno的博客 1655

深入理解JVM——深入解析虚拟机字节码执行引擎

而对于执行引擎来讲,在活动线程中,只有位于栈顶的方法才是在运行的,也只有位于栈顶的栈帧才是生效的,称其为“当前栈帧”,与这个栈帧所关联的方法被称作为“当前方法”。所有方法调用的目标方法在Class文件里面都是一个常量池中的符号引用,在类加载的解析阶段,会将其中的一部分符号引用转化为直接引用,这种解析能够成立的前提是:方法在程序真正运行之前就有一个可确定的调用版本,并且这个方法的调用版本在运行期是不可改变的。另外在概念模型中,两个不同栈帧作为不同方法的虚拟机栈的元素,是完全相互独立的。

weixin_57323780的博客 232

深入理解JVM—虚拟机字节码执行引擎

虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的,而虚拟机的执行引擎则是由软件自行实现的,因此可以不受物理条件制约地定制指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式。Java虚拟机以方法作为最基本的执行单元,“栈帧”(Stack Frame)则是用于支持虚拟机进行方法调用和方法执行背后的数据结构,它也是虚拟机运行时数据区中的虚拟机栈(Virtual Machine Stack)的栈元素。

Hx_blog的博客 250

深入理解JVM6-虚拟机字节码执行引擎

虚拟机字节码执行引擎: 不同的虚拟机实现里,可能会有解释执行(边解释边执行)和编译执行(通过即时编译器产生本地代码执行)的混合模式或单独的某种模式。 一、运行时栈帧结构 编译时,栈帧中需要多大的局部变量表,多深的操作数栈就已经确定,存储在方法表的Code属性中。因此一个栈帧需要分配的内存大小,不会受到程序运行期间变量数据的影响,而仅仅取决于具体的虚拟机实现。 栈帧存储了方法的局部变量表、操作数栈...

pugongying_95的博客 233

【深入理解JVM】学习笔记——-8、虚拟机字节码执行引擎

八、虚拟机字节码执行引擎 你只管努力, ——剩下的交给时光。 老规矩,先上图,大致了解一下: 一. 概述 执行引擎是 Java 虚拟机最核心的组成部分之一。“虚拟机” 是一个相对于 “物理机” 的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、硬件、指令集和操作系统层面上的,而虚拟机的执行引擎则是由自己实现的,因此可以自行制定指令集与执行引擎的结构体...

你只管努力, 369

深入理解JVM总结——虚拟机字节码执行引擎

执行引擎是Java虚拟机最核心的组成部分之一。物理机和虚拟机都有执行代码的能力。区别在于物理机的执行引擎是直接建立在处理器、硬件、指令集和操作系统层面上的,而虚拟机的执行引擎则是由自己实现的,因此可以自行指定指令集与执行引擎的结构体系,并且能够执行那些不被硬件直接支持的指令集格式。 虚拟机执行引擎在执行Java代码的时候分为解释执行(通过解释器执行)和编译执行(通过即时编译器产生本地代码执行),也

nalanmingdian的博客 517

深入理解JVM-虚拟机字节码执行引擎

8.1 概述 执行引擎是字节码是最核心的组成部分之一。执行引擎在执行java代码的时候,可能会有解释执行(通过解释器执行),和编译执行(通过及时编译器产生本地代码执行)二种选择。但是外观上看起来是一致的:输入的是字节码文件,处理的过程是字节码解析的等效过程,输出的是执行的结果。 8.2 运行时栈帧结构 栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构。栈帧存储了局部变量表,操作数栈,动态

liang0000zai的专栏 1091
上一篇: 并发编程实战 - 线程池的使用
下一篇: 并发编程实战 - 避免活跃性危险【死锁场景】
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值