栈虚拟机和寄存器虚拟机,有什么不同?
本来这节内容是打算直接讲字节码指令的,但讲之前又必须得先讲指令集架构,而指令集架构又分为两种,一种是基于栈的,一种是基于寄存器的。
那不妨我们这节就单独来讲讲栈虚拟机和寄存器虚拟机,它们有什么不同,以及各自的优缺点。
栈和寄存器
关于栈这个数据结构,我们前面曾讲过,戳链接直达。
寄存器(Register)是中央处理器(CPU)内用来暂存指令、数据和地址的存储器,也是 CPU 中读写最快的存储器。

图片来源于cxuan
从硬件层面来说,栈位于内存当中,而寄存器位于 CPU 当中,这也是为什么,我们通常会说,基于寄存器架构的虚拟机会比基于栈的虚拟机快的原因。
基于栈的虚拟机
前面我们讲 JDK 的发展历程时,提到了 Hotspot VM,它是血缘最正统的 Java 虚拟机。

HotSpot VM 是基于栈的一种虚拟机,当 Java 程序运行时,HotSpot VM 加载编译后的字节码文件(也就是.class 文件),其解释器或JIT编译器会读取文件中的字节码指令,将它们解释(或编译)为机器码。
方法调用和执行过程中的数据(如局部变量和中间结果)会存储在栈(操作数栈,下面会讲)中,字节码指令操作这些数据,然后执行程序逻辑。
下面这幅图我们之前在讲JVM 是如何运行 Java 代码的时候讲过。

main 方法被执行的时候,JVM 会创建一个栈帧(Stack Frame),通过存储局部变量表、操作数栈、动态链接、方法出口等信息来支撑和完成方法的执行,栈帧就是虚拟机栈中的子单位。

栈帧本身也是一种栈结构,用于支持虚拟机进行方法调用和方法执行,遵循 LIFO 的原则,每个栈帧都包含了一个方法的运行信息,每个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈和出栈的过程。

图片来源于网络,作者浣熊say
虚拟机栈是线程私有的,每个线程都有自己的 Java 虚拟机栈。方法调用时都会创建一个新的栈帧,该栈帧被推入虚拟机栈,成为当前活动栈帧。
- 入栈:方法调用时,虚拟机栈会为这个方法分配一个栈帧,这个栈帧被压入虚拟机栈,成为当前的活动栈帧。PC 寄存器指向当前栈帧的指令,执行方法的指令序列从该地址开始。
- 出栈:方法执行完成后,对应的栈帧会被移除,控制权回到前一个栈帧,前一个栈帧中的返回值成为当前活动栈帧的一个操作数,继续执行。
其中的操作数栈(Operand Stack)也是一种栈结构,用于保存方法执行时的中间结果、参数和返回值。当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的。
在方法执行的过程中,操作数栈被用于执行各种字节码指令。例如,将两个数字相加的指令会从操作数栈中弹出两个数字,将它们相加,然后将结果压入操作数栈中。
另外,操作数栈的内容是临时的,它的生命周期和方法的生命周期是一样的,当方法执行结束后,操作数栈也会被销毁。

R 大曾在知乎的贴子里提到过:
VM 当初设计的时候非常重视代码传输和存储的开销,因为假定的应用场景是诸如手持设备、机顶盒之类的嵌入式应用,所以要代码尽量小;外加基于栈的实现更简单(无论是在源码编译器的一侧还是在虚拟机的一侧),而且主要设计者 James Gosling 的个人经验上也对这种做法非常熟悉(例如他之前实现过 PostScript 的虚拟机,也是基于栈的指令集),所以就选择了基于栈。
我们简单来看一下基于栈的虚拟机方法执行的过程,以下面的代码为例:
int a = 33;
int b = 44;
int c = a + b;
通过 javap -c Main 命令可以查看对应的字节码,如下所示:
Compiled from "Main.java"
public class com.github.paicoding.forum.test.javabetter.jvm.Main {public static void main(java.lang.String[]);Code:0: bipush 332: istore_13: bipush 445: istore_26: iload_17: iload_28: iadd9: istore_310: return
}
我们用图来说明指令执行的过程,大致如下。

- iload_0 将 33 压入操作数栈中
- iload_1 将 44 压入操作数栈中
- iadd 将操作数栈中的 33 和 44 弹出,相加后将结果 77 压入操作数栈中
- istore_2 将栈顶的 77 弹出,存入局部变量表中下标为 2 的位置
关于字节码指令的具体释义,我们放到下一节去细讲,这里主要是带大家体会一下基于栈的虚拟机和基于寄存器的虚拟机之间的差别。
基于寄存器的虚拟机
那除了有基于栈的虚拟机实现,当然也有基于寄存器的虚拟机实现,比如 LuaVM,负责执行 Lua 语言,一门轻量级的脚本语言,可戳链接了解。
5.0 之前的 Lua 其实是用基于栈的指令集,到 5.0 才改为用基于寄存器的。出于两点考虑,一是减少数据移动次数,降低数据迁移带来的拷贝开销;二是减少虚拟指令条数,提高指令执行效率。

好,我们就基于 lua 来看一下基于寄存器的虚拟机方法执行的过程。
第一步,安装 lua,这里我用的是 macOS,直接用 brew 安装就好了。
brew install lua
Windows 用户可以查看这个文档:lua-users wiki: Building Lua In Windows For Newbies
也可以通过 Lua for Windows 来完成安装:
Releases · rjpcomputing/luaforwindows · GitHub
我们来编写一段简单的 lua 代码,保存为 example.lua。
local a = 33
local b = 44
local c = a + b
然后查看字节码指令。
luac -l example.lua
结果如下:

main <example.lua:0,0> (6 instructions at 0x600002144080)
0+ params, 3 slots, 1 upvalue, 3 locals, 0 constants, 0 functions
这是函数的描述,表示这是 example.lua 文件中的主函数。它包含 6 条指令。函数不接受参数(0+ params),有 3 个本地变量槽位(3 slots),1 个闭包变量(1 upvalue),3 个本地变量(3 locals),没有常量(0 constants)和内部函数(0 functions)。
接下来是具体的指令:
- VARARGPREP 0:准备变长参数,用于处理传入的参数。
- LOADI 0 33:将整数 33 加载到寄存器 0。
- LOADI 1 44:将整数 44 加载到寄存器 1。
- ADD 2 0 1:将寄存器 0 和寄存器 1 中的值相加,并将结果存放在寄存器 2。对应于脚本中两个数值的加法操作。
- MMBIN 0 1 6; add:这是一个元方法(metamethod)调用,用于处理加法操作。这指示 Lua 虚拟机查找并执行
add元方法。元方法是 Lua 中用于重载标准操作符的特殊方法。 - RETURN 3 1 1; 0 out:返回操作,将寄存器 3 中的值作为返回值。
1 1表示从寄存器 3 返回一个值,0 out指没有额外的返回值。
小结
基于栈的优点是可移植性更好、指令更短、实现起来简单,但不能随机访问栈中的元素,完成相同功能所需要的指令数也比寄存器的要多,需要频繁的入栈和出栈。
基于寄存器的优点是速度快,有利于程序运行速度的优化,但操作数需要显式指定,指令也比较长。
相关文章:
栈虚拟机和寄存器虚拟机,有什么不同?
本来这节内容是打算直接讲字节码指令的,但讲之前又必须得先讲指令集架构,而指令集架构又分为两种,一种是基于栈的,一种是基于寄存器的。 那不妨我们这节就单独来讲讲栈虚拟机和寄存器虚拟机,它们有什么不同࿰…...
Windows下基于fping进行批量IP测试
fping是Linux下一个很好用的IP测试工具,结合代码可以完成批量的IP测试,在网络调试中用途很广。本文是基于fping for Windows结合bat批处理,定制的测试脚本样例。 一、程序信息 本次测试使用fpingV5.1 for Windows版,版本信息如下…...
一款实用的Word文档图片转换与水印保护工具
目录 前言软件功能简介软件实现方法及关键代码 1. Word 文档转图片的实现2. 图片水印添加功能3. 生成数字指纹(哈希值)4. 保存图片信息到 JSON 文件 软件的实际使用场景软件操作指南 1. 下载和安装2. 操作流程 总结 1,前言 在日常办公和内…...
优化用于传感应用的衬底集成波导技术
ANSYS HFSS 是一款功能强大的电磁仿真软件,支持为微流体生物传感器应用设计和分析衬底集成波导 (SIW) 技术。它为快速设计优化、材料选择、系统集成和虚拟原型制作提供了一个强大的平台。借助 ANSYS HFSS,研究人员和工程师可以高效…...
Java多态特性的向上转型
Java的多态特性通过向上转型来实现。向上转型指的是将子类对象赋值给父类引用变量的操作。这样做的好处是可以使用父类引用变量来调用子类对象的方法。 例如,有一个父类Animal和一个子类Dog,可以这样进行向上转型: Animal animal new Dog(…...
C++ 判断语句的深入解析
C 判断语句的深入解析 C 是一种广泛使用的编程语言,以其高效性和灵活性著称。在 C 中,判断语句是控制程序流程的关键组成部分,它们允许程序根据不同的条件执行不同的代码路径。本文将深入探讨 C 中的判断语句,包括 if、else if、…...
15分钟学 Go 第 33 天:项目结构
第33天:项目结构 目标:了解Go项目的典型结构 在Go语言的开发中,项目结构的合理性直接影响着代码的可维护性、可扩展性和团队协作效率。本篇文章将深入探讨Go语言的典型项目结构,并提供实际示例代码和相关的流程图。 一、Go项目…...
conda迁移虚拟环境路径
方法一:使用软连接 ln -s ~/Anaconda3/envs /new/path/envs 方法二:修改~/.condarc文件 1.打开~/.condarc文件 #添加下面参数 envs_dirs: - /newpath/anaconda3/envs pkgs_dirs: - /newpath/anaconda3/pkgs 2. source ~/.bashrc 3.查看是否成功con…...
(八)JavaWeb后端开发——Tomcat
目录 1.Web服务器概念 2.tomcat 1.Web服务器概念 服务器:安装了服务器软件的计算机服务器软件:接收用户的请求,处理请求,做出响应web服务器软件:在web服务器软件中,可以部署web项目,让用户通…...
yocto中通常不直接修改提供的recipes的bb文件
不直接在 Yocto 官方提供的 recipe 中修改 通常是创建新的 metadata 和 recipe 来配置相关软件编译等过程 主要有以下几个原因: 1. 便于维护和升级 隔离自定义修改:Yocto 官方的 recipe 可能会随着版本更新而变化。如果直接修改官方 recipe࿰…...
智能座舱相关术语全解及多模态交互在智能座舱中的应用
文章目录 座舱相关术语全解1. 智能座舱2. UFS3. 多模态交互4. 3D虚拟引擎5. AR/VR6. GNSS7. TTS8. DPU9. 摄像头10. 屏幕/显示器11. 音频12. 无线连接13. 其他组件 多模态交互在智能座舱中有以下一些应用 座舱相关术语全解 1. 智能座舱 智能座舱(intelligent cabi…...
【Fastjson反序列化漏洞:深入了解与防范】
一、Fastjson反序列化漏洞概述 Fastjson是一款高性能的Java语言JSON处理库,广泛应用于Web开发、数据交换等领域。然而,由于fastjson在解析JSON数据时存在安全漏洞,攻击者可以利用该漏洞执行任意代码,导致严重的安全威胁。 二、F…...
【OJ题解】C++实现反转字符串中的每个单词
💵个人主页: 起名字真南 💵个人专栏:【数据结构初阶】 【C语言】 【C】 【OJ题解】 题目要求:给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。 题目链接: 反转字符串中的所…...
万字长文详解Hive聚合函数 grouping sets、cube、rollup原理、语法、案例和优化
目录 原理与语法 使用场景 多维度报表生成 复杂的数据分析 实际案例 原理与语法 与GROUPINGSETS的区别 实际案例 原理与语法 与CUBE的对比 实际案例 执行效率比较 优化建议 Hive提供了三个强大的高级聚合函数: GROUPING SETS 、 CUBE 和 ROLLUP ,用于处理复杂的…...
数列分块入门
本期是数列分块入门。其中的大部分题目来自hzwer在LOJ上提供的数列分块入门系列。 Blog:here (其实是对之前分块的 blog 的整理补充) sto hzwer orz %%% [转载] ---------------------------------------------------------------------------------…...
SPRD Android 14 Launcher 3 中添加长按桌面图标启动自由窗口模式功能
本文将介绍如何在SPRD Android 14 Launcher 3 中实现一个功能,使用户可以通过长按应用图标来启动自由窗口模式。这一功能的实现将提升多任务处理能力和应用使用体验。 修改的文件列表 以下是主要涉及的文件及其修改内容: QuickstepLauncher.java:添加自由窗口快捷方式的支…...
WebSocket详解:从前端到后端的全栈理解
文章目录 前言一、WebSocket简介1.1 WebSocket的特点 二、WebSocket的工作原理2.1 握手过程2.2 数据传输 三、WebSocket在前端的应用四、WebSocket在后端的应用五、WebSocket的局限与解决方案结语 前言 随着互联网技术的发展,传统的HTTP协议在某些场景下的局限性逐…...
SOLIDWORKS 2025加快装配体设计 确保可制造性
在快速变化的制造业环境中,SOLIDWORKS作为一款CAD软件,始终致力于提供有效、智能且可靠的解决方案,以满足设计师和工程师对装配体设计的多样化需求。随着SOLIDWORKS 2025版本的发布,其在加快装配体设计、确保可制造性方面取得了显…...
简单题:计算从位置 x 到 y 的最少步数| 豆包MarsCode AI刷题
题目解析:计算从位置 x 到 y 的最少步数 题目描述 题目要求从整数位置 x 移动到整数位置 y,每一步可以将当前位置增加或减少,且每步的增加或减少的值必须是连续的整数。首末两步的步长必须是 1。要求求出从 x 到 y 的最少步数。 思路分析 …...
HTML 基础标签——表单标签<form>
文章目录 1. `<form>` 标签:定义表单容器2. `<input>` 标签:多用途输入控件3. `<textarea>` 标签:多行文本输入框4. `<select>` 标签:下拉选择框5. `<option>` 标签:下拉菜单选项6. `<button>` 标签:按钮元素7. `<label>` 标签…...
如何用OpenCore Legacy Patcher让老旧Mac焕发新生:5分钟快速上手指南
如何用OpenCore Legacy Patcher让老旧Mac焕发新生:5分钟快速上手指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 还在为你的老旧Mac无法升级到…...
移动端大语言模型本地部署:从模型轻量化到推理引擎实战
1. 项目概述:当GPT遇见移动端,一个开源项目的诞生最近在GitHub上闲逛,发现了一个挺有意思的项目,叫Taewan-P/gpt_mobile。光看名字,你大概就能猜到它的核心:把类似GPT这样的大语言模型(LLM&…...
别再死记硬背了!用MATLAB手把手教你画根轨迹图(附代码与避坑指南)
MATLAB实战:从零绘制根轨迹图的完整指南与避坑技巧 在控制系统的设计与分析中,根轨迹图是理解系统动态特性的重要工具。传统教学中,学生往往被要求死记硬背绘制规则,却难以理解其实际应用价值。本文将彻底改变这一现状——通过MAT…...
3步实现专业级AI换脸:roop-unleashed创新方案指南
3步实现专业级AI换脸:roop-unleashed创新方案指南 【免费下载链接】roop-unleashed Evolved Fork of roop with Web Server and lots of additions 项目地址: https://gitcode.com/gh_mirrors/ro/roop-unleashed 在数字创意飞速发展的今天,AI换脸…...
Taotoken用量看板如何帮助个人开发者管理月度预算
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Taotoken用量看板如何帮助个人开发者管理月度预算 对于独立工作的个人开发者而言,项目预算往往是决定技术选型与使用策…...
保姆级教程:用Python+NumPy复现经典Laplacian曲面编辑算法(附源码)
从理论到代码:Python实现Laplacian曲面编辑的完整指南 在三维图形处理领域,Laplacian曲面编辑技术因其出色的细节保持能力而备受推崇。这项技术允许开发者对三维模型进行直观的变形操作,同时保持模型表面的几何细节不被破坏。本文将带您从零开…...
深度解析Scarab:空洞骑士模组管理器的专业实现与架构设计
深度解析Scarab:空洞骑士模组管理器的专业实现与架构设计 【免费下载链接】Scarab An installer for Hollow Knight mods written with Avalonia. 项目地址: https://gitcode.com/gh_mirrors/sc/Scarab 空洞骑士模组管理器Scarab为玩家提供了高效、专业的模组…...
JetBrains IDE 30天试用重置:一键解决方案的完整实践指南
JetBrains IDE 30天试用重置:一键解决方案的完整实践指南 【免费下载链接】ide-eval-resetter 项目地址: https://gitcode.com/gh_mirrors/id/ide-eval-resetter 当您正专注于代码调试时,IDE突然弹出"评估期已结束"的红色警告…...
AI助手API开发资源全指南:从入门到实战的宝藏清单
1. 项目概述:一个为AI助手API开发者量身打造的“藏宝图”如果你正在或打算基于OpenAI的Assistant API、Anthropic的Claude API,或是其他主流AI平台的助手接口来构建应用,那么你大概率会遇到一个经典困境:官方文档虽然详尽…...
飞书自动化开发实战:从脚本编写到事件驱动架构设计
1. 项目概述:飞书自动化,从“手动挡”到“自动驾驶”的进化 如果你每天的工作,有超过30%的时间是在飞书里重复着“点击-填写-发送”的枯燥操作,比如手动拉取数据生成日报、定时向群聊推送消息、或者根据特定条件审批流程…...
