网站备案需要年检吗/百度搜索推广产品
JVM入门到入土-Java虚拟机寄存器指令集与栈指令集
HotSpot虚拟机中的任何操作都需要入栈和出栈的步骤。
由于跨平台性的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功能需要更多的指令。
参考资料
- Java虚拟机规范(JavaSE8)
- 深入理解Java虚拟机
JVM的两大指令集特点
基于栈式架构的特点
设计和实现更简单,适用于资源受限的系统(HotSpot虚拟机就基于此):
- 避开了寄存器的分配难题: 使用零地址指令方式分配。
- 指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈。
- 指令集更小编译器容易实现。
- 不需要硬件支持,可移植性更好,更好实现跨平台
基于寄存器架构的特点
典型的应用是x86的二进制指令集: 比如传统的PC以及Android的Davlik虚拟机。
- 指令集架构则完全依赖硬件,可移植性差
- 性能优秀和执行更高效,花费更少的指令去完成一项操作。
- 在大部分情况下,基于寄存器架构的指令集往往都以一地址指令、二地址指令和三地址指令为主,而基于栈式架构的指令集却是以零地址指令为主。
获取栈指令集-指令javap
注意:如果你使用JDK17,可能会出现找不到控制台指令的问题(因为默认安装不会配置该指令),去JDK17的安装目录将bin添加到环境变量即可
先编译一个简单的1+2
程序:
public class StackOneTest {public static void main(String[] args) {int a = 1;int b = 2;int c = a+b;}
}
然后使用javap -c class文件全名
,我们将在控制台得到如下内容:
D:\CodeProjects\Eclipse\StackTest\bin\testjava>javap -c StackOneTest.class
Compiled from "StackOneTest.java"
public class testjava.StackOneTest {public testjava.StackOneTest();Code:0: aload_01: invokespecial #8 // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: iconst_11: istore_12: iconst_23: istore_24: iload_15: iload_26: iadd7: istore_38: return
}
由于手里没有基于寄存器的指令集实验环境,可自行查阅查看方法
栈指令集字节码的语义
字节码指令集设计概述
在 Java 虚拟机的指令集中,大多数的指令都包含了其所操作的数据类型信息。例如,
iload
指令用于从局部变量表中加载int
类型的数据到操作数栈中,而ad
指加载的则是float
类型的数据。这两个指令的操作可能会是由同一段代码来实现的,但它们必须拥有各自独立的操作码。对于大部分与数据类型相关的字节码指令来说,它们的操作码助记符中都有特殊的字符来表明该指令为哪种数据类型服务:i
代表对int
型的数据操作,l
代表long
,s
代表short
,b
代表byte
,c
代表char
,f
代表float
,d
代表double
,a
代表reference
。也有一些指令的助记符没有明确用字母指明数据类型,例如arraylength
指令,它没有代表数据类型的特殊字符,但操作数永远只能是一个数组类型的对象。还有另外一些指令,例如,无条件跳转指令goto
则是与数据类型无关的。因为 Java 虚拟机的操作码长度只有一个字节,所以包含了数据类型的操作码给指令集的设计带来了很大的压力。如果每一种与数据类型相关的指令都支持 Java 虚拟机的所有运行时数据类型,那恐怕就会超出一个字节所能表示的数量范围了。因此,Java 虚拟机的指令集对于特定的操作只提供了有限的类型相关指令,换句话说,指令集将会故意设计成非完全独立的(not orthogonal,即并非每种数据类型和每一种操作都有对应的指令)。有一些单独的指令可以在必要的时候用来将一些不支持的类型转换为可支持的类型。
表 2-2 列举了 Java 虚拟机所支持的字节码指令集。用数据类型列所代表的特殊字符替换
opcode
列的指令模板中的T
,就可以得到一个具体的字节码指令。如果在表中指令模板与数据类型两列共同确定的单元格为空,则说明虚拟机不支持对这种数据类型执行这项操作。例如,load
指令有操作int
类型的iload
,但是没有操作byte
类型的同类指令。请注意,从表 2-2 中可以看出,大部分的指令都没有支持整数类型byte
、char
和short
,甚至没有任何指令支持boolean
类型。编译器会在编译期或运行期将byte
和short
类型的数据带符号扩展(sign-extend)为相应的int
类型数据,将boolean
和char
类型数据零位扩展(zero-extend)为相应的int
类型数据。与之类似,在处理boolean
、byte
、short
和char
类型的数组时,也会转换为使用对应的int
类型的字节码指令来处理。因此,操作数的实际类型为boolean
、byte
、char
及short
的大多数操作,都可以用操作数的运算类型(computational type)为int
的指令来完成。from : Java虚拟机规范(JavaSE8)
附表:
实际类型与关系映射表:
加载与存储指令集
加载本地变量到操作数栈的指令:
指令 | 描述 |
---|---|
iload | 将 int 类型加载到操作数栈 |
iload <n> | 将指定索引的 int 类型加载到操作数栈 |
lload_<n> | 将指定索引的 long 类型加载到操作数栈 |
fload | 将 float 类型加载到操作数栈 |
fload <n> | 将指定索引的 float 类型加载到操作数栈 |
dload | 将 double 类型加载到操作数栈 |
dload <n> | 将指定索引的 double 类型加载到操作数栈 |
aload | 将引用类型加载到操作数栈 |
aload <n> | 将指定索引的引用类型加载到操作数栈 |
存储操作数栈到局部变量表的指令:
指令 | 描述 |
---|---|
istore | 将 int 类型存储到局部变量表 |
istore <n> | 将 int 类型存储到指定索引的局部变量 |
lstore <n> | 将 long 类型存储到指定索引的局部变量 |
fstore | 将 float 类型存储到局部变量表 |
fstore <n> | 将 float 类型存储到指定索引的局部变量 |
dstore | 将 double 类型存储到局部变量表 |
dstore <n> | 将 double 类型存储到指定索引的局部变量 |
astore | 将引用类型存储到局部变量表 |
astore_<n> | 将引用类型存储到指定索引的局部变量 |
加载常量到操作数栈的指令:
指令 | 描述 |
---|---|
bipush | 将带符号的 byte 常量(-128~127)加载到操作数栈 |
sipush | 将带符号的 short 常量(-32768~32767)加载到操作数栈 |
ldc | 将 int, float 或 String 类型的常量加载到操作数栈 |
ldc_w | 与 ldc 类似,但用于更大的常量池索引 |
ldc2_w | 将 long 或 double 类型的常量加载到操作数栈 |
aconst_null | 将 null 加载到操作数栈 |
iconst_m1 | 将整数 -1 加载到操作数栈 |
iconst <i> | 将整数常量加载到操作数栈 |
lconst <1> | 将长整数常量1加载到操作数栈 |
fconst <f> | 将浮点数常量加载到操作数栈 |
dconst <d> | 将双精度浮点数常量加载到操作数栈 |
扩充局部变量表的访问索引或立即数的指令:
指令 | 描述 |
---|---|
wide | 扩展下一条指令使用的局部变量索引的宽度 |
算数指令集
算术指令:
操作类型 | 指令 |
---|---|
加法 | iadd 、ladd 、fadd 、dadd |
减法 | isub 、Isub 、fsub 、dsub |
乘法 | imul 、mul 、fmul 、dmul |
除法 | idiv 、ldiv 、fdiv 、ddiv |
求余 | irem 、Irem 、frem 、drem |
逻辑位运算指令:
操作类型 | 指令 |
---|---|
按位或 | ior 、lor |
按位与 | iand 、land |
按位异或 | ixor 、lxor |
其他运算指令:
操作类型 | 指令 |
---|---|
求负值 | ineg 、Ineg 、fneg 、dneg |
移位 | ishl 、ishr 、iushr 、Ishl 、Ishr 、lushr |
局部变量自增 | iinc |
比较 | dcmpg 、dcmpl 、fcmpg 、fcmpl 、Icmp |
栈指令集字节码分析
main方法中的算数字节码
D:\CodeProjects\Eclipse\StackTest\bin\testjava>javap -c StackOneTest.class
Compiled from "StackOneTest.java"
public class testjava.StackOneTest {public testjava.StackOneTest();Code:0: aload_01: invokespecial #8 // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: iconst_11: istore_12: iconst_23: istore_24: iload_15: iload_26: iadd7: istore_38: return
}
从上述字节码不难看出,JVM
先执行了StackOneTest
对象的构造,然后将这个对象变量加载到了操作数栈(默认构造器),我们重点来看main
中的指令集:
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
先将两个常量1
,2
加载到操作数栈,并且进行了存储,接下来:
4: iload_1
5: iload_2
6: iadd
7: istore_3
加载了两个变量a
,b
到操作数栈,然后使用算数指令进行相加,最后进行存储结果(这里的第三个变量未使用,变量加载可能被编译器优化掉了),我们稍加修改:
可以发现在使用了第三个变量后,JVM
进行了正确的变量加载
含方法的字节码分析
我们增加一个方法来进一步分析:
public class StackOneTest {public static int add(int a, int b) {return a+b;}public static void main(String[] args) {int a = 1;int b = 2;int c = add(a, b);System.out.println(c);}
}
从这里可知 invokestatic
应该为调用方法的指令集,其运行也是和上一个大同小异,不过需要注意不同返回值类型的Treturn
指令(T是借用泛型里的一个代号)
多次入栈字节码分析
修改代码:
public class StackOneTest {public static void main(String[] args) {int a = 1;int b = 2;int c = 3;int d = a+b;int e = a+c;}
}
相同方法进行分析:
可以发现其字节码也是逐行进行操作的,在变量d
,e
位置的处理和第一处也是类似的,只不过a
进行了重复入栈
相关文章:

JVM入门到入土-Java虚拟机寄存器指令集与栈指令集
JVM入门到入土-Java虚拟机寄存器指令集与栈指令集 HotSpot虚拟机中的任何操作都需要入栈和出栈的步骤。 由于跨平台性的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。优点是跨平台,指令集小&#x…...

MS2244模拟开关可Pin to Pin兼容NJM2244
MS2244 是一款集成的视频开关,实现三输入视频或音频信号的三选一。可Pin to Pin兼容NJM2244。 芯片集成了 75Ω驱动电路,可以直接驱动电视监控器。芯片工作电压 5V~12V,带宽 10MHz,抗串扰 70dB (4.43MHz)。另外芯片还集…...

PostgreSQL 可观测性最佳实践
简介 软件简述 PostgreSQL 是一种开源的关系型数据库管理系统 (RDBMS),它提供了许多可观测性选项,以确保数据库的稳定性和可靠性。 可观测性 可观测性(Observability)是指对数据库状态和操作进行监控和记录,以便在…...

51单片机相关寄存器
前言 单片机复习的时候对应寄存器的记忆感觉很混乱,这里进行一下整理,后面的单词是我用来辅助记忆的,可能并不是表示原本的含义。 P3口的第二功能 0RXD 串行数据输入口 1TXD串行数据输出口2INT0外部中断0输入3INT1外部中断1输入4T0定时器0外部计数输入…...

二叉树进阶题目(超详解)
文章目录 前言根据二叉树创建字符串题目分析写代码 二叉树的层序遍历题目分析 写代码二叉树的层序遍历II题目分析写代码 二叉树的最近公共祖先题目分析写代码时间复杂度 优化思路优化的代码 二叉搜索树与双向链表题目分析写代码 从前序与中序遍历序列构造二叉树题目分析写代码从…...

W6100-EVB-Pico评估版介绍
文章目录 1 简介2 硬件资源2.1 硬件规格2.2 引脚定义2.3 工作条件 3 参考资料3.1 Datasheet3.2 原理图3.3 尺寸图(尺寸:mm)3.4 参考例程 4 硬件协议栈优势 1 简介 W6100-EVB-Pico是一款基于树莓派RP2040和全硬件TCP/IP协议栈以太网芯片W6100的…...

嵌入式面试准备
题目都摘于网上 嵌入式系统中经常要用到无限循环,如何用C编写死循环 while(1){}或者for(;😉 内存分区 代码区,全局区(全局变量,静态变量,以及常量),栈区,堆区 const关键…...

在Linux Docker中部署RStudio Server,实现高效远程访问
🌈个人主页:聆风吟 🔥系列专栏:网络奇遇记、Cpolar杂谈 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 📋前言一. 安装RStudio Server二. 本地访问三. Linux 安装cpolar四. 配置RStudio serv…...

EternalBlue【永恒之蓝】漏洞详解(复现、演示、远程、后门、入侵、防御)内容丰富-深入剖析漏洞原理-漏洞成因-以及报错解决方法-值得收藏!
漏洞背景: 1.何为永恒之蓝? 永恒之蓝(Eternal Blue)爆发于2017年4月14日晚,是一种利用Windows系统的SMB协议漏洞来获取系统的最高权限,以此来控制被入侵的计算机。甚至于2017年5月12日, 不法分子…...

长链接与在线文件
什么是在线文件 常见的聊天工具,比如。。。微信,你可以发送一个文件给对端,即使对端不在线,这个文件也可以暂存在服务器上面,直到接收端上线消费或者超时,这个叫离线文件。与之对应的,在线文件要…...

Python内置数据类型等入门语(句)法
内置数据类型 数字(Number)关键字: int 、float、complex字符串(String)关键字:单引号,双引号 三引号都可以表示,8 种内置类型都可转为字符串类型列表(List) 关键符号 […...

ElasticSearch之RestClient笔记
1. ElasticSearch 1.1 倒排索引 1.2 ElasticSearch和Mysql对比 1.3 RestClient操作 导入依赖 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.15.…...

饥荒Mod 开发(二二):显示物品信息
饥荒Mod 开发(二一):超大便携背包,超大物品栏,永久保鲜 饥荒Mod 开发(二三):显示物品栏详细信息 饥荒中的物品没有详细信息,基本上只有一个名字,所以很多物品的功能都不知道,比如浆果吃了也不知…...

Microsoft Edge使用方法和心得
Microsoft Edge使用方法和心得 大家好,我是豪哥,一名来自杭州的Java程序员,今天我想分享一下我对Microsoft Edge的使用方法和心得。作为一名热爱编程的程序员,我发现一个高效的浏览器对于我们的工作和学习至关重要。而Microsoft …...

Kafka操作指令笔记
查堆积用命令查: ./kafka-consumer-groups.sh --bootstrap-server {kafka集群地址} --describe --group {消费组名称}bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --all-groups #查看所有组别的积压情况可以通过grep、awk或其他文…...

WAVE SUMMIT+ 2023倒计时2天,传文心一言将曝最新进展!
传文心一言将曝最新进展! 亮点一:趋势引领,“扛把子”文心一言将曝新进展亮点二:干货十足,硬核低门槛开发秘籍大放送亮点三:蓄势待发,大模型赋能产业正当时亮点四:群星闪耀ÿ…...

Crow:Middlewares 庖丁解牛5 context
Crow:Middlewares 庖丁解牛4 partial_context-CSDN博客 基于partial_context再来解释context namespace detail {template<typename... Middlewares>struct partial_context : public pop_back<Middlewares...>::template rebind<partial_context>, public…...

CentOS 7 设置网络
CentOS 7 设置网络 正常情况 ①登陆进去之后使用下面的命令修改文件 echo ONBOOTyes >> /etc/sysconfig/network-scripts/ifcfg-ens33②如果是虚拟机重启后使用如下命令进行查看IP地址 ip addr注:到这里如果显示有两部分,则代表网络设置成功&a…...

装饰器模式(Decorator)
装饰器模式(Decorator Pattern)是一种结构型设计模式,用于动态地给一个对象添加额外的职责。装饰器提供了一个灵活的替代扩展功能的方案,相比继承更加灵活。 在Java中,装饰器模式通常涉及以下几个部分: 组件(Component):定义一个对象接口,可以给这些对象动态添加职责…...

关于“Python”的核心知识点整理大全34
目录 第13 章 外星人 13.1 回顾项目 game_functions.py 13.2 创建第一个外星人 13.2.1 创建 Alien 类 alien.py 13.2.2 创建 Alien 实例 alien_invasion.py 13.2.3 让外星人出现在屏幕上 game_functions.py 13.3 创建一群外星人 13.3.1 确定一行可容纳…...

设计模式--抽象工厂模式
实验4:抽象工厂模式 本次实验属于模仿型实验,通过本次实验学生将掌握以下内容: 1、理解抽象工厂模式的动机,掌握该模式的结构; 2、能够利用抽象工厂模式解决实际问题。 [实验任务]:人与肤色 使用抽象…...

浅析海博深造
文章目录 深造作用 留学种类 选专业 择校 申请流程 申请方式 深造作用 1、个人能力提升(学术专业、语言、新文化或新生活方式) 2、更好的职业发展(起点更高、结交新朋友或扩大社交圈) 3、北京上海落户优惠 4、海外居留福…...

【Hive_05】企业调优1(资源配置、explain、join优化)
1、 计算资源配置1.1 Yarn资源配置1.2 MapReduce资源配置 2、 Explain查看执行计划(重点)2.1 Explain执行计划概述2.2 基本语法2.3 案例实操 3、分组聚合优化3.1 优化说明(1)map-side 聚合相关的参数 3.2 优化案例 4、join优化4.1…...

synchronized
⭐ 作者:小胡_不糊涂 🌱 作者主页:小胡_不糊涂的个人主页 📀 收录专栏:JavaEE 💖 持续更文,关注博主少走弯路,谢谢大家支持 💖 synchronized 1. 特性1.1 互斥1.2 可重入 …...

Vue在页面上添加水印
第一步:在自己的项目里创建一个js文件;如图所示我在在watermark文件中创建了一个名为waterMark.js文件。 waterMark.js /** 水印添加方法 */ let setWatermark (str1, str2) > {let id 1.23452384164.123412415if (document.getElementById(id) …...

SQL server 数据库练习题及答案(练习2)
使用你的名字创建一个数据库 创建表: 数据库中有三张表,分别为student,course,SC(即学生表,课程表,选课表) 问题: --1.分别查询学生表和学生修课表中的全部数据。--2.查询成绩在70到80分之间…...

minicube搭建golang容器服务
引言 最近在自己电脑上搭建一个小型k8s环境,以学习云原生相关内容。这里我主要分为三部分记录: 容器及容器编排理论环境安装相关rpcx服务实战 还在调试中,先总结整理下,这里后续补充上我的github工程链接。 一、容器及容器编排理…...

图片批量处理:图片批量缩放,高效调整尺寸的技巧
在数字媒体时代,图片处理已是日常生活和工作中不可或缺的一部分。有时候要批量处理图片,如缩放图片尺寸,以满足不同的应用需求。现在一起来看看办公提效式具如何高效的将图片批量处理方法,快速、准确地批量调整图片尺寸操作。 下…...

直接插入排序【从0-1学数据结构】
文章目录 💗 直接插入排序Java代码C代码JavaScript代码稳定性时间复杂度空间复杂度 我们先来学习 直接插入排序, 直接排序算是所有排序中最简单的了,代码也非常好实现,尽管直接插入排序很简单,但是我们依旧不可以上来就直接写代码,一定要分析之后才开始写,这样可以提…...

C++/CLI——1简介
C/CLI——1简介 如果你是.net程序员,不免会用到C/C写的库。对于简单的调用,可以直接使用DllImport来完成就可以,详情可参考C#调用C/C从零深入讲解。但是对于复杂的C类和对象,尤其是类似于OCC的大型C项目,DllImport可能…...