深入浅出JVM(十)之字节码指令(下篇)

上篇文章深入浅出JVM(九)之字节码指令(上篇)已经深入浅出说明加载存储、算术、类型转换的字节码指令,本篇文章作为字节码的指令的下篇,深入浅出的解析各种类型字节码指令,如:方法调用与返回、控制转义、异常处理、同步等

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

方法调用与返回指令

方法调用指令

非虚方法: 静态方法,私有方法,父类中的方法,被final修饰的方法,实例构造器

与之对应不是非虚方法的就是虚方法了

  • 普通调用指令

    • invokestatic: 调用静态方法
    • invokespecial: 调用私有方法,父类中的方法,实例构造器 方法,final方法
    • invokeinterface: 调用接口方法
    • invokevirtual: 调用虚方法

    使用invokestaticinvokespecial指令的一定是非虚方法

    使用invokeinterface指令一定是虚方法(因为接口方法需要具体的实现类去实现)

    使用invokevirtual指令可能是虚方法

  • 动态调用指令

    • invokedynamic: 动态解析出需要调用的方法再执行

    jdk 7 出现invokedynamic,支持动态语言

测试虚方法代码

  • 父类
 public class Father {public static void staticMethod(){System.out.println("father static method");}​public final void finalMethod(){System.out.println("father final method");}​public Father() {System.out.println("father init method");}​public void overrideMethod(){System.out.println("father override method");}}
  • 接口
 public interface TestInterfaceMethod {void testInterfaceMethod();}
  • 子类
 public class Son extends Father{​public Son() {//invokespecial 调用父类init 非虚方法super();//invokestatic 调用父类静态方法 非虚方法staticMethod();//invokespecial 调用子类私有方法 特殊的非虚方法privateMethod();//invokevirtual 调用子类的重写方法 虚方法overrideMethod();//invokespecial 调用父类方法 非虚方法super.overrideMethod();//invokespecial 调用父类final方法 非虚方法super.finalMethod();//invokedynamic 动态生成接口的实现类 动态调用TestInterfaceMethod test = ()->{System.out.println("testInterfaceMethod");};//invokeinterface 调用接口方法 虚方法test.testInterfaceMethod();}​@Overridepublic void overrideMethod(){System.out.println("son override method");}​private void privateMethod(){System.out.println("son private method");}​public static void main(String[] args) {new Son();}}

image-20210426234249850.png

方法返回指令

方法返回指令: 方法结束前,将栈顶元素(最后一个元素)出栈 ,返回给调用者

根据方法的返回类型划分多种指令

image-20210515103425506.png

操作数栈管理指令

通用型指令,不区分类型

  • 出栈

    • pop/pop2出栈1个/2个栈顶元素
  • 入栈

    • dup/dup2 复制栈顶1个/2个slot并重新入栈

    • dup_x1 复制栈顶1个slot并插入到栈顶开始的第2个slot下

    • dup_x2复制栈顶1个slot并插入到栈顶开始的第3个slot下

    • dup2_x1复制栈顶2个slot并插入到栈顶开始的第3个slot下

    • dup2_x2复制栈顶2个slot并插入到栈顶开始的第4个slot下

      • 插入到具体的slot计算: dup的系数 + _x的系数

控制转义指令

条件跳转指令

通常先进行比较指令,再进行条件跳转指令

比较指令比较结果-1,0,1再进行判断是否要跳转

条件跳转指令: 出栈栈顶元素,判断它是否满足条件,若满足条件则跳转到指定位置

image-20210515164609270.png

image-20210515165351883.png

注意: 这种跳转指令一般都"取反",比如代码中第一个条件语句是d>100,它第一个条件跳转指令就是ifle小于等于0,满足则跳转,不满足则按照顺序往下走

比较条件跳转指令

比较条件跳转指令 类似 比较指令和条件跳转指令 的结合体

image-20210515180004587.png

image-20210515181000595.png

多条件分支跳转指令

多条件分支跳转指令是为了switch-case提出的

tableswitch用于case值连续的switch多条件分支跳转指令,效率好

lookupswitch用于case值不连续的switch多条件分支跳转指令(虽然case值不连续,但最后会对case值进行排序)

tableswitch

image-20210515182307183.png

lookupswitch

image-20210515183527055.png

对于String类型是先找到对应的哈希值再equals比较确定走哪个case的

无条件跳转指令

无条件跳转指令就是跳转到某个字节码指令处

goto经常使用

jsr,jsr_w,ret不怎么使用了

image-20210515183640270.png

异常处理指令

throw抛出异常对应athrow: 清除该操作数栈上所有内容,将异常实例压入调用者操作数栈上

使用try-catch/try-final/throws时会产生异常表

异常表保存了异常处理信息 (起始、结束位置、字节码指令偏移地址、异常类在常量池中的索引等信息)

athrow

image-20210515192750444.png

异常表

image-20210515193437666.png

异常还会被压入栈或者保存到异常表中

同步控制指令

synchronized作用于方法时,方法的访问标识会有ACC_SYNCHRONIZED表示该方法需要加锁

synchronized作用于某个对象时,对应着monitorentry加锁字节码指令和 monitorexit解锁字节码指令

Java中的synchronized默认是可重入锁

  • 当线程要访问需要加锁的对象时 (执行monitorentry)
  1. 先查看对象头中加锁次数,如果为0说明未加锁,获取后,加锁次数自增
  2. 如果不为0,再查看获取锁的线程是不是自己,如果是自己就可以访问,加锁次数自增
  3. 如果不为0且获取锁线程不是自己,就阻塞

当线程释放锁时 (执行monitorexit)会让加锁次数自减

image-20210515195912727.png

为什么会有2个monitorexit ?

程序正常执行应该是一个monitorentry对应一个monitorexit的

如果程序在加锁的代码中抛出了异常,没有释放锁,那不就会造成其他阻塞的线程永远也拿不到锁了吗

所以在程序抛出异常时(跳转PC偏移量为15的指令)继续往下执行,抛出异常前要释放锁

总结

本篇文章作为字节码指令的下篇,深入浅出的解析方法调用与返回,操作数栈的入栈、出栈,控制转义,异常和同步相关字节码指令

方法调用指令分为静态、私有、接口、虚、动态方法等,返回指令则主要是以i、l、f、d、a开头的return指令分别处理不同类型的返回值

操作数栈中的出栈指令常用pop相关指令,入栈(复制栈顶元素并插入)常用dup相关指令

控制转义指令中条件跳转指令是判断栈顶元素来进行跳转,比较条件跳转指令是通过两个栈顶元素比较来判断跳转,多条件分支跳转是满足switch,常在异常时进行goto无条件跳转

异常处理指令用于抛出异常,清除操作数栈并将异常压入调用者操作数栈顶

同步控制指令常使用monitorentrymonitoryexit,为了防止异常时死锁,抛异常前执行monitoryexit

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

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

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络:思科实验【2-MAC地址、IP地址、ARP协议及总线型以太网的特性】

🌈个人主页:godspeed_lucip 🔥 系列专栏:Cisco Packet Tracer实验 本文对应的实验报告源文件请关注微信公众号程序员刘同学,回复思科获取下载链接。 实验目的实验环境实验内容MAC地址、IP地址、ARP协议总线型以太网的…

2024-02-25 Unity 编辑器开发之编辑器拓展7 —— Inspector 窗口拓展

文章目录 1 SerializedObject 和 SerializedProperty2 自定义显示步骤3 数组、List 自定义显示3.1 基础方式3.2 自定义方式 4 自定义属性自定义显示4.1 基础方式4.2 自定义方式 5 字典自定义显示5.1 SerizlizeField5.2 ISerializationCallbackReceiver5.3 代码示例 1 Serialize…

音频smmu问题之smmu学习

一、音频smmu 内存访问问题 在工作中,遇到一个smmu问题,主要log信息如下: arm-smmu 15000000.apps-smmu: Unhandled arm-smmu context fault from soc:spf_core_platform:qcom,msm-audio-ion! arm-smmu 15000000.apps-smmu: FAR 0x0000000…

【考研数学】基础阶段习题1800和660怎么选❓

我建议以1800题为主 1800题包含基础和强化两部分,基础部分题量很大,类型也很全面,并且难度一点也不高,适合基础不好的学生来做。 660题难度比较大,不适合基础阶段做。 660题虽然名字叫基础训练,但是不适…

超详细!彻底说明白Redis持久化

本文已收录至Github,推荐阅读 👉 Java随想录 微信公众号:Java随想录 文章目录 Redis持久化方式RDBfork 函数与写时复制RDB 相关配置 AOFAOF 文件解读AOF 的写入与同步AOF 重写AOF重写的实现AOF 重写面临的问题AOF重写缓存区 AOF相关配置AOF …

车载电子电器架构 —— OEM基础技术概念开发流程

车载电子电器架构 —— 基础技术概念开发 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗…

Spring Cloud Gateway官方文档学习

文章目录 推荐写在前面一、熟悉Gateway基本概念与原理1、三大概念2、工作流程 二、基本使用路由断言的两种写法 三、路由断言工厂1、After路由断言工厂2、Before路由断言工厂3、Between路由断言工厂4、Cookie路由断言工厂5、Header路由断言工厂6、Host路由断言工厂7、Method路由…

《插入排序》与《选择排序》

目录 前言: 排序的概念: 插入排序: 1.直接插入排序: 2.希尔排序( 缩小增量排序 ): 选择排序: 1.直接选择排序: 2.快速排序: hore思想: 挖坑法: 双指针法&#…

【风格迁移】CAST:对比学习,从图像特征而非其二阶统计量(Gram矩阵)中学习风格

CAST:对比学习,从图像特征而非其二阶统计量(Gram矩阵)中学习风格 提出背景5 why 分析5 so分析 CAST 框架多层风格投影器领域增强模块生成网络 效果对比 StyleGAN 提出背景 论文:https://arxiv.org/pdf/2205.09542.pdf…

如何使用移动端设备在公网环境远程访问本地黑群晖

文章目录 前言本教程解决的问题是:按照本教程方法操作后,达到的效果是前排提醒: 1. 搭建群晖虚拟机1.1 下载黑群晖文件vmvare虚拟机安装包1.2 安装VMware虚拟机:1.3 解压黑群晖虚拟机文件1.4 虚拟机初始化1.5 没有搜索到黑群晖的解…

linux常用的网络命令实战分享

文章目录 ifup/down命令ifconfig命令观察网络接口信息修改接口参数增加虚拟网络接口 route命令查看路由表增加路由表规则删除路由表规则 IP 命令ip linkip addr设定路由 ip route arp 命令 在实际研发运维工作中常常会涉及到网关相关的操作和知识,这里对linux下常用…

电脑msvcp100.dll丢失了怎么办?msvcp100.dll丢失的5种解决方法

当计算机系统中无法找到msvcp100.dll文件,或者遭遇msvcp100.dll丢失的情况时,可能会引发一系列运行问题和功能障碍。msvcp100.dll是Microsoft Visual C Redistributable Package的一部分,这是一个至关重要的动态链接库文件,对于许…

LeetCode第二题: 两数相加

文章目录 题目描述示例 解题思路 - 迭代法Go语言实现 - 迭代法算法分析 解题思路 - 模拟法Go语言实现 - 模拟法算法分析 解题思路 - 优化模拟法主要方法其他方法的考虑 ‍ 题目描述 给出两个非空的链表用来表示两个非负的整数。其中,它们各自的位数是按照逆序的方…

Spring Boot利用Kaptcha生成验证码

生成验证码 我们在登录或注册某个网站的时候,会需要我们输入验证码,才能登录注册,那么如何生成验证码呢?其实,生成验证码我们可以用Java Swing在后台内存里的区域画一个出来,但是非常麻烦,所以…

【JavaEE】_HttpServlet类

目录 1. init方法 2. destory方法 3. service方法 4. servlet生命周期 前文已经提及到:servlet是tomcat提供的,用于操作HTTP协议的一组API,可以将这组API理解为HTTP服务器的框架; 编写一个servlet程序,往往都要继…

基于Java SSM框架实现音乐播放器管理系统项目【项目源码+论文说明】计算机毕业设计

ssm音乐播放器管理系统演示录像2020 摘要 随着社会的发展,计算机的优势和普及使得音乐播放器管理系统的开发成为必需。音乐播放器管理系统主要是借助计算机,通过对首页、音乐推荐、付费音乐、论坛信息、个人中心、后台管理等信息进行管理。减少管理员的…

groovy:XmlParser 读 Freeplane.mm文件,生成测试案例.csv

Freeplane 是一款基于 Java 的开源软件,继承 Freemind 的思维导图工具软件,它扩展了知识管理功能,在 Freemind 上增加了一些额外的功能,比如数学公式、节点属性面板等。 强大的节点功能,不仅仅节点的种类很多&#xff…

蓝桥杯《修剪灌木》

题目描述 爱丽丝要完成一项修剪灌木的工作。有 N 棵灌木整齐的从左到右排成一排。爱丽丝在每天傍晚会修剪一棵灌木,让灌木的高度变为 0 厘米。爱丽丝修剪灌木的顺序是从最左侧的灌木开始,每天向右修剪一棵灌木。当修剪了最右侧的灌木后,她会…

动态规划--状态转移

解码方法 1.题目 2.思路 1)我们定义一个数组dp,其中dp[i]表示字符串s的前i个字符的解码方法总数。初始化时,dp[0]为1,因为空字符串有一种解码方式。dp[1]的值取决于第一个字符是否是0,如果不是0,则有一种…

C/C++暴力/枚举/穷举题目(刷蓝桥杯基础题的进!)

目录 前言 一、百钱买百鸡 二、百元兑钞 三、门牌号码(蓝桥杯真题) 四、相乘(蓝桥杯真题) 五、卡片拼数字(蓝桥杯真题) 六、货物摆放(蓝桥杯真题) 七、最短路径(蓝…