深入浅出JVM(九)之字节码指令(上篇)

本篇文章主要围绕字节码的指令,深入浅出的解析各种类型字节码指令,如:加载存储、算术、类型转换、对象创建与访问、方法调用与返回、控制转义、异常处理、同步等

由于字节码指令种类太多,本文作为上篇概述加载存储、算术、类型转换的字节码指令

使用idea中的插件jclasslib查看编译后的字节码指令

字节码指令集

大部分指令先以i(int)、l(long)、f(float)、d(double)、a(引用)开头

其中byte、char、short、boolean在hotspot中都是转成int去执行(使用int类型的字节码指令)

字节码指令大致分为:

  1. 加载与存储指令
  2. 算术指令
  3. 类型转换指令
  4. 对象创建与访问指令
  5. 方法调用与返回指令
  6. 操作数栈管理指令
  7. 控制转义指令
  8. 异常处理指令
  9. 同步控制指令

在hotspot中每个方法对应的一组字节码指令

这组字节码指令在该方法所对应的栈帧中的局部变量表和操作数栈上进行操作

字节码指令包含字节码操作指令 和 操作数 (操作数可能是在局部变量表上也可能在常量池中还可能就是常数)

加载与存储指令

加载

加载指令就是把操作数加载到操作数栈中(可以从局部变量表,常量池中加载到操作数栈)

  • 局部变量表加载指令

    • i/l/f/d/aload 后面跟的操作数就是要去局部变量表的哪个槽取值
    • iload_0: 去局部变量表0号槽取出int类型值
  • 常量加载指令

    • 可以根据加载的常量范围分为三种(从小到大) const < push < ldc

存储

存储指令就是将操作数栈顶元素出栈后,存储到局部变量表的某个槽中

  • 存储指令

    • i/l/f/d/astore 后面跟的操作数就是要存到局部变量表的哪个槽
    • istore_1:出栈栈顶int类型的元素保存到局部变量表的1号槽

注意: 编译时就知道了局部变量表应该有多少槽的位置 和 操作数栈的最大深度(为节省空间,局部变量槽还会复用)

image.png 从常量池加载100存储到局部变量表1号槽,从常量池加载200存储到局部变量表2号槽(其中局部变量表0号槽存储this)

算术指令

算术指令将操作数栈中的俩个栈顶元素出栈作运算再将运算结果入栈

使用的是后缀表达式(逆波兰表达式),比如 3 4 + => 3 + 4

注意

  1. 当除数是0时会抛出ArithmeticException异常
  2. 浮点数转整数向0取整
  3. 浮点数计算精度丢失
  4. Infinity 计算结果无穷大
  5. Nan 计算结果不确定计算值
     public void test1() {double d1 = 10 / 0.0;//InfinitySystem.out.println(d1);​double d2 = 0.0 / 0.0;//NaNSystem.out.println(d2);​//向0取整模式:浮点数转整数//5System.out.println((int) 5.9);//-5System.out.println((int) -5.9);​​//向最接近数舍入模式:浮点数运算//0.060000000000000005System.out.println(0.05+0.01);​//抛出ArithmeticException: / by zero异常System.out.println(1/0);}

类型转换指令

类型转换指令可以分为宽化类型转换窄化类型转换(对应基本类型的非强制转换和强制转换)

宽化类型转换

小范围向大范围转换

  • int -> long -> float -> double

    • i2li2fi2d
    • l2fl2d
    • f2d

byte、short、char 使用int类型的指令

注意: long转换为float或double时可能发生精度丢失

     public void test2(){long l1 =  123412345L;long l2 =  1234567891234567899L;​float f1 = l1;//结果: 1.23412344E8 => 123412344//                l1 =  123412345LSystem.out.println(f1);​double d1 = l2;//结果: 1.23456789123456794E18 => 1234567891234567940//                          l2 =  1234567891234567899LSystem.out.println(d1);}

窄化类型转换

大范围向小范围转换

  • int->byte、char、short: i2bi2ci2s
  • long->int: l2i
  • float->long、int: f2lf2i
  • double->float、long、int: d2fd2ld2i

如果long,float,double要转换为byte,char,short可以先转为int再转为相对应类型

窄化类型转换会发生精度丢失

NaN和Infinity的特殊情况:

     public void test3(){double d1 = Double.NaN;double d2 = Double.POSITIVE_INFINITY;​int i1 = (int) d1;int i2 = (int) d2;//0System.out.println(i1);//trueSystem.out.println(i2==Integer.MAX_VALUE);​long l1 = (long) d1;long l2 = (long) d2;//0System.out.println(l1);//trueSystem.out.println(l2==Long.MAX_VALUE);​float f1 = (float) d1;float f2 = (float) d2;//NaNSystem.out.println(f1);//InfinitySystem.out.println(f2);}

NaN转为整型会变成0

正无穷或负无穷转为整型会变成那个类型的最大值或最小值

对象创建与访问指令

对象创建与访问指令: 创建指令、字段访问指令、数组操作指令、类型检查指令

创建指令

new: 创建实例

newarray: 创建一维基本类型数组

anewarray: 创建一维引用类型数组

multianewarray: 创建多维数组

注意: 这里的创建可以理解为分配内存,当多维数组只分配了一维数组时使用的是anewarray

image-20210514230240390.png

字段访问指令

getstatic: 对静态字段进行读操作

putstatic: 对静态字段进行写操作

getfield: 对实例字段进行读操作

putfield: 对实例字段进行写操作

读操作: 把要进行读操作的字段入栈

写操作: 把要写操作的值出栈再写到对应的字段

image-20210515093103500.png

数组操作指令
  • b/c/s/i/l/f/d/a aload : 表示将数组中某索引元素入栈 (读)

    • 需要的参数从栈顶依次向下: 索引位置、数组引用
  • b/c/s/i/l/f/d/a astore: 表示将某值出栈并写入数组某索引元素 (写)

    • 需要的参数从栈顶依次向下: 要写入的值、索引位置、数组引用

image-20210515094055002.png

注意: b开头的指令对byte和boolean通用

  • arraylength: 先将数组引用出栈再将获得的数组长度入栈

image-20210515095603614.png

类型检查指令

instanceof: 判断某对象是否为某类的实例

checkcast: 检查引用类型是否可以强制转换

image-20210515095311597.png

总结

由于字节码指令种类多篇幅长,将会分为上、下篇来深入浅出解析字节码指令,本篇作为上篇深入浅出的解析字节码指令介绍、加载存储指令、算术指令、类型转换指令以及对象创建与访问指令

字节码指令大部分以i、l、f、d、a开头,分别含义对应int、long、float、double、引用,其中byte、char、short、boolean会转换为int来执行

字节码指令分为字节码操作指令和需要操作的数据,数据可能来源于局部变量表或常量池

加载指令从局部变量表或者常量池中加载数据,存储指令将存储到对应局部变量表的槽中,实例方法的局部变量表的0号槽常用来存储this,如果方法中变量是局部存在的还可能会复用槽

算术指令为各种类型和各种算术提供算术规则,在操作数栈中使用后缀表达式对操作数进行算术

类型转换分为宽化与窄化,都可能存在精度损失

对象创建与访问指令中包含创建对象,访问实例、静态字段,操作数组,类型检查等指令

最后(一键三连求求拉~)

本篇文章笔记以及案例被收入 gitee-StudyJava、 github-StudyJava 感兴趣的同学可以stat下持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

本文由博客一文多发平台 OpenWrite 发布!

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

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

相关文章

IT廉连看——C语言——操作符

IT廉连看—操作符 c语言中有许多操作符&#xff0c;可以用于对变量进行各种不同的操作 一、算术操作符 - * / % 除了 % 操作符之外&#xff0c;其他的几个操作符可以作用于整数和浮点数。 对于 / 操作符如果两个操作数都为整数&#xff0c;执行整数除法。而只要有浮点…

vue+nodejs+uniapp婚纱定制婚庆摄影系统 微信小程序 springboot+python

目前移动互联网大行其道&#xff0c;人人都手中拿着智能机&#xff0c;手机手机&#xff0c;手不离机&#xff0c;如果开发一个用在手机上的程序软件&#xff0c;那是多么的符合潮流&#xff0c;符合管理者和客户的理想。本次就是开发婚庆摄影小程序&#xff0c;有管理员&#…

基础光学系列:(三)揭秘机器视觉中的光圈、焦距与景深的作用

​今天来聊聊成像原理、光圈、焦距和景深&#xff0c;这些概念在摄影、摄像以及机器视觉领域都非常重要。它们共同影响着成像设备捕捉图像的质量和特性。让我们一一解析这些概念以及它们如何在机器视觉行业中应用。 成像原理&#xff1a;怎样把外面的世界捕捉进来 想象一下&a…

大厂面试-美团高频考察算法之重排链表

本文学习目标或巩固的知识点 学习如何处理链表重排类题目 巩固反转链表巩固快慢指针巩固合并链表 提前说明&#xff1a;算法题目来自力扣、牛客等等途径 &#x1f7e2;表示简单 &#x1f7e1;表示中等 &#x1f534;表示困难 &#x1f92e;表示恶心 博主真实经历&#xff0c;…

前后端分离Vue+ElementUI+nodejs蛋糕甜品商城购物网站95m4l

本文主要介绍了一种基于windows平台实现的蛋糕购物商城网站。该系统为用户找到蛋糕购物商城网站提供了更安全、更高效、更便捷的途径。本系统有二个角色&#xff1a;管理员和用户&#xff0c;要求具备以下功能&#xff1a; &#xff08;1&#xff09;用户可以修改个人信息&…

LabVIEW储氢材料循环寿命测试系统

LabVIEW储氢材料循环寿命测试系统 随着氢能技术的发展&#xff0c;固态储氢技术因其高密度和安全性成为研究热点。储氢材料的循环寿命是衡量其工程应用的关键。然而&#xff0c;传统的循环寿命测试设备存在成本高、测试效率低、数据处理复杂等问题。设计了一种基于LabVIEW软件…

uniapp 使用 z-paging组件

使用 z-paging 导入插件 获取插件进行导入 自定义上拉加载样式和下拉加载样式 页面结构 例子 搭建页面 <template><view class"content"><z-paging ref"paging" v-model"dataList" query"queryList"><templ…

【VSCode】SSH Remote 通过跳板机连开发机提示“bash行1 powershell未找到命令”

需求背景 因为需要&#xff0c;在家我需要挂上公司VPN然后SSH连到跳板机&#xff0c;然后再从跳板机SSH进开发机。 问题背景 跳板机进开发机输入完密码显示 bash行1 powershell未找到命令VSCode SSH Remote跳板机配置请自行搜素其他文章config配置 注意其中ssh.exe地址请根据…

并发编程(5)共享模型之不可变

7 共享模型之不可变 本章内容 不可变类的使用不可变类设计无状态类设计 7.1 日期转换的问题 问题提出 下面的代码在运行时&#xff0c;由于 SimpleDateFormat 不是线程安全的, 有很大几率出现 java.lang.NumberFormatException 或者出现不正确的日期解析结果&#xff0c;…

规则持久化(Sentinel)

规则持久化 基于Nacos配置中心实现推送 引入依赖 <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId> </dependency> 流控配置文件 [{"resource":"/order/flow",…

六、Vuex

六、Vuex 6.1 Vuex是什么 概念&#xff1a;专门在 Vue 中实现集中式状态&#xff08;数据&#xff09;管理的一个 Vue 插件&#xff0c;对 vue 应 用中多个组件的共享状态进行集中式的管理&#xff08;读/写&#xff09;&#xff0c;也是一种组件间通信的方 式&#xff0c;且…

vue3获取环境变量import.meta.env

vitevue的时候环境变量的获取方式变成如下&#xff1a; console.log(import.meta.env)

ARMv8-AArch64 的异常处理模型详解之异常向量表vector tables

目录 一&#xff0c;AArch64 异常向量表 二&#xff0c;栈指针以及SP寄存器的选择 三&#xff0c;从异常返回 一&#xff0c;AArch64 异常向量表 异常向量表&#xff08;vector tables&#xff09;是一组存放于普通内存&#xff08;normal memory&#xff09;空间的&#xf…

【机器学习科学库】全md文档笔记:Jupyter Notebook和Matplotlib使用(已分享,附代码)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论人工智能相关知识。主要内容包括&#xff0c;了解机器学习定义以及应用场景&#xff0c;掌握机器学习基础环境的安装和使用&#xff0c;掌握利用常用的科学计算库对数据进行展示、分析&#xff0c;学会使用jupyter note…

vue从flask获取数据并显示

记录一个前后端分离遇到的问题&#xff0c;即vue前端从flask后端获取数据。具体描述如下&#xff1a;flask只负责连接数据库并获取数据库的数据&#xff0c;并返回给前端vue&#xff1b;vue则需要获取后端返回的数据并显示。 方法如下&#xff0c;分别用一个vue组件和一个flas…

【网站项目】488服装店销售管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

迷你世界之建筑生成球体

local x0,y0,z00,30,0--起点坐标 local dx,dy,dz60,60,60--外切长方体横纵竖长度 local count,all0,dx*dy*dz--计数&#xff0c;总数 local m,k10000,0--单次生成方块数&#xff0c;无用循环值 local x,y,z0,0,0--当前坐标 local demath.random(2,19)/2 local id600--方块…

中兴通讯携吉林移动迈向5G-A新阶段,完成3CC技术应用

日前&#xff0c;中兴通讯携手中国移动吉林移动分公司&#xff0c;在5G-A领域取得新突破。具体来说&#xff0c;双方基于MTK芯片M80终端&#xff0c;完成了5G-A三载波聚合试点&#xff0c;实测下行速率达到理论峰值4.25Gbps&#xff0c;相比2.6G单载波速率提升2.5倍。如此成绩&…

C++面试题精选与解析

C面试题精选与解析 一、基础与语法 请问C中的指针和引用有什么区别&#xff1f; 指针是一个变量&#xff0c;存储的是另一个变量的内存地址。指针可以被重新赋值以指向另一个不同的对象。而引用是某个变量的别名&#xff0c;一旦引用被初始化为一个变量&#xff0c;就不能改变…

LLM权重量化

LLM权重量化 浮点表示的背景知识Nave 8位量化使用LLM.int8() 进行8位量化结论References 大型语言模型(llm)以其广泛的计算需求而闻名。通常&#xff0c;模型的大小是通过将**参数的数量(大小)乘以这些值的精度(数据类型)**来计算的。为了节省内存&#xff0c;可以通过称为量化…