当前位置: 首页 > news >正文

JVM学习日记(十二)Day12

我们上一篇主要讲了字节码文件和方法的字节码指令的简单执行过程,相信大家对字节码又有了一个新的理解,今天咱们还是对字节码指令进行进一步的解析。

魔数

之前主包应该也有说过这个词但是应该没有详细的说(具体在哪里说主包已经忘了😁),之前也说过JVM不仅仅是可以运行Java的项目,其实也是可以运行其他语言的项目,因为JVM其实只认识字节码文件,只要编译后是字节码文件那么就可以在JVM上运行,那怎么确定他是不是字节码文件呢,这个就和魔数有关系,魔数是一个4字节固定的值,它的值是 ​**0xCAFEBABE​(16进制),即 ​CA FE BA BE**,标志着他是一个合法的字节码文件,我们使用 xxd <文件名>可以查看,前4个字节就是魔数。(16进制一个字符可以用4位二进制表示,而一个字节8位也就是8bit,也就是说一个16进制字符等于0.5个字节)

 我们一直说的字节码文件本质上其实就是一个二进制流,而JVM读取加载的其实也是这个二进制流,所以要让一个JVM运行程序不一定需要从磁盘去读取,也可以来自于网络只要符合字节码即魔数就可以被加载、识别、使用。

那这个流又是什么?我们常说的IO流这个流到底指的是什么?其实值的就是不分隔的以0和1组成的文件,为什么叫做流也就是一个抽象的概念,主包认为就算水一样从源头开始到尽头中间是没有隔断的,这个就是一个完整的流,而主包上面的图是一个16进制的那为什么又说是二进制流?因为这个是为了我们人阅读而特意解析的,其实在磁盘里任何文件都是二进制的流,只是用了不同的解析器解析给我们看的,不然一堆010101我们也看不懂的。

Class文件的结构

虽然昨天主包已经讲了字节码文件的各个部分,但是可能还是比较模糊,现在就根据昨天的内容总结一下具体的结构。大概就是这样画的丑凑合看。

 

这个是一个字节码文件的结构表格,但是随着JDK的版本不断变化,可能有所不同的大家做一个了解就可以了,类型这个U 表示使用后面的数字表示数量,合起来就是使用的字节数量,而后面几个info就是表了,因为表的数量是不确定的所以就没有像其他的一样表示了,字节码中所以的表都是2个部分组成,一个是计数器一个就是表,其实可以理解为索引了这个计数器。另外就是这个字符串常量池是从1开始计算的,所以数量是-1,那为什么是这样呢?因为有些情况不需要任何指向这个常量池,所以0就用来表示无任何指向。

 字节码指令

字节码指令是指JVM使用一个字节长度的代表特定操作意义的数字(称为操作码),以及其后面跟着的0到多个代表此操作需要的参数(称为操作数)组成的。但由于JVM限制了长度所以操作码不能超过256条,

大部分的指令其实都包含了数据类型和操作,如iload,i表示int类型,load表示从局部变量表加载入操作数栈。

数据类型大小指令前缀示例指令说明
int32 位iiloadiaddiconst_0最常用,布尔/字符也用 int
long64 位llloadladdlconst_0需 2 个栈槽(占用 2 个位置)
float32 位ffloadfaddfconst_0
double64 位ddloaddadddconst_0需 2 个栈槽
byte8 位(无,用 i)bipush实际按 int 处理
short16 位(无,用 i)sipush实际按 int 处理
char16 位(无,用 i)i2c(转换指令)UTF-16 编码
boolean1 位(无,用 i)-JVM 中用 int 表示(0/1)
引用类型不固定aaloadString,对象,数组都是引用类型

 JVM 字节码指令按功能可分为 ​9 大类,涵盖数据操作、流程控制、对象操作等。以下是详细分类和代表性指令:

1. 常量加载指令(Load Constants)​

作用​:将常量(数字、字符串、null等)压入操作数栈。

指令操作数栈变化作用示例
iconst_0无(隐含 0[] → [0]将 int 型 0 压入栈顶int a = 0;
bipush 10单字节立即数(10[] → [10]将单字节整数(-128~127)压入栈顶int b = 10;
ldc #5常量池索引(#5[] → [value]从常量池加载复杂常量(如字符串)String s = "hi";
aconst_null[] → [null]将 null 引用压入栈顶Object o = null;

2. 局部变量操作指令(Local Variables)​

作用​:读取或存储局部变量表中的数据。

指令操作数栈变化作用示例
iload_1无(隐含索引 1[] → [value]加载第 1 个 int 局部变量到栈顶int x = localVar;
astore_2无(隐含索引 2[ref] → []将栈顶引用存储到第 2 个局部变量o = new Object();
wide iload 2562 字节索引(256[] → [value]加载第 256 个局部变量(扩展索引)加载大索引变量

3. 算术运算指令(Arithmetic)​

作用​:对栈顶数据进行数学运算(加、减、乘、除等)。

指令操作数栈变化作用示例
iadd[a, b] → [a+b]int 加法(弹出两数,压入结果)int c = a + b;
fmul[f1, f2] → [f1*f2]float 乘法float f = f1 * f2;
ineg[x] → [-x]int 取负int y = -x;

4. 类型转换指令(Type Conversion)​

作用​:强制转换栈顶数据的类型。

指令操作数栈变化作用示例
i2f[int] → [float]将 int 转为 float(float) 10
d2i[double] → [int]将 double 转为 int(可能截断)(int) 3.14
checkcast常量池索引[ref] → [ref]校验引用类型是否匹配指定类(String) obj

5. 对象操作指令(Object Operations)​

作用​:创建对象、访问字段或数组元素。

指令操作数栈变化作用示例
new #3类常量池索引(#3[] → [ref]创建类实例并压入引用new Object()
getfield #5字段常量池索引(#5[ref] → [value]读取对象的实例字段值obj.field
aaload[array, index] → [element]加载引用数组的指定元素arr[0]

6. 方法调用指令(Method Invocation)​

作用​:调用静态方法、实例方法或动态方法。

指令操作数栈变化作用示例
invokevirtual #7方法常量池索引(#7[ref, arg1, arg2...] → [result]调用实例方法(虚方法分派)obj.method()
invokestatic #9方法常量池索引(#9[arg1, arg2...] → [result]调用静态方法Math.max(a, b)
invokedynamic动态调用点(BootstrapMethod)按需操作栈动态语言支持(如 Lambda)() -> {}

7. 流程控制指令(Control Flow)​

作用​:实现条件分支、循环、方法返回等控制逻辑。

指令操作数栈变化作用示例
ifeq +10跳转偏移量(+10[int] → []如果栈顶 int 为 0 则跳转if (a == 0)
goto -20跳转偏移量(-20无条件跳转到指定偏移量while (true)
ireturn[int] → []从方法返回 int 值return 42;

8. 栈操作指令(Stack Manipulation)​

作用​:调整操作数栈的结构(复制、丢弃、交换等)。

指令操作数栈变化作用示例
dup[a] → [a, a]复制栈顶值new Object()(双引用)
pop[a] → []丢弃栈顶值丢弃返回值
swap[a, b] → [b, a]交换栈顶两个值交换变量值

9. 其他指令(Miscellaneous)​

作用​:同步、空操作等特殊功能。

指令操作数栈变化作用示例
monitorenter[ref] → []进入同步块(获取对象锁)synchronized (obj)
nop空操作(占位或调试)无实际作用

以上的字节码指令只是部分,具体的还是要上官网或者去搜索的,有兴趣的小伙伴可以自行去了解,这里推荐一位博主,写的非常好Java字节码指令详解,1 万字20 张图带你彻底掌握字节码指令 | 二哥的Java进阶之路 

总结

本篇是对上一篇的补充,主要还是说的是字节码相关的内容,好了就这。

http://www.lryc.cn/news/606307.html

相关文章:

  • 8K、AI、低空智联,H.266能否撑起下一代视频通路?
  • vue 开发总结:从安装到第一个交互页面-与数据库API
  • 逻辑回归详解:从数学原理到实际应用
  • 三坐标测量仪攻克深孔检测!破解新能源汽车阀体阀孔测量难题
  • MySQL 8.0 OCP 1Z0-908 题目解析(39)
  • Verilog与SytemVerilog差别
  • 文法中的间接左递归
  • 行业热点丨仿真历史数据难以使用?如何利用几何深度学习破局,加速汽车工程创新
  • 【BUUCTF系列】[HCTF 2018]WarmUp1
  • 第15届蓝桥杯C++青少组中级组选拔赛(STEMA)2024年3月10日真题
  • 大模型流式长链接场景下 k8s 优雅退出 JAVA
  • 永磁同步电机无速度算法--直流误差抑制自适应二阶反推观测器
  • 公路坑槽检测分析原理和思路
  • Java——数组及Java某些方法、二维数组
  • #C语言——刷题攻略:牛客编程入门训练(一):简单输出、基本类型
  • C++游戏开发(2)
  • 一次性接收大量上传图片,后端优化方式
  • 代码随想录算法训练营第五十七天|图论part7
  • Qt 消息弹窗 Toast
  • 两款免费数据恢复软件介绍,Win/Mac均可用
  • python后端之DRF框架(下篇)
  • 《零基础入门AI:传统机器学习核心算法(决策树、随机森林与线性回归)》
  • wxPython 实践(五)高级控件
  • 【ad-hoc构造】P10033 「Cfz Round 3」Sum of Permutation|普及+
  • vscode插件开发(腾讯混元)
  • Go再进阶:结构体、接口与面向对象编程
  • Cesium 快速入门(三)Viewer:三维场景的“外壳”
  • 基于深度学习的医学图像分析:使用BERT实现医学文本分类
  • 零信任网络概念及在网络安全中的应用
  • 【数据库】MySQL 详细安装与基础使用教程(8版本下载及安装)