关于后端:深入浅出JVM十之字节码指令下篇

10次阅读

共计 3544 个字符,预计需要花费 9 分钟才能阅读完成。

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

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

办法调用与返回指令

办法调用指令

非虚办法: 静态方法,公有办法,父类中的办法,被 final 润饰的办法,实例结构器

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

  • 一般调用指令

    • invokestatic: 调用静态方法
    • invokespecial: 调用公有办法,父类中的办法, 实例结构器 <init> 办法,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();}
 ​
     @Override
     public 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();
     }
 }

办法返回指令

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

依据办法的返回类型划分多种指令

操作数栈治理指令

通用型指令,不辨别类型

  • 出栈

    • 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 再进行判断是否要跳转

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

留神: 这种跳转指令个别都 ” 取反 ”,比方代码中第一个条件语句是 d >100,它第一个条件跳转指令就是 ifle 小于等于 0,满足则跳转,不满足则依照程序往下走

比拟条件跳转指令

比拟条件跳转指令 相似 比拟指令和条件跳转指令 的结合体

多条件分支跳转指令

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

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

lookupswitch用于 case 值不间断的 switch 多条件分支跳转指令(尽管 case 值不间断, 但最初会对 case 值进行排序)

tableswitch

lookupswitch

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

无条件跳转指令

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

goto常常应用

jsr,jsr_w,ret不怎么应用了

异样解决指令

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

应用 try-catch/try-final/throws 时会产生异样表

异样表保留了异样解决信息 (起始、完结地位、字节码指令偏移地址、异样类在常量池中的索引等信息)

athrow

异样表

异样还会被压入栈或者保留到异样表中

同步控制指令

synchronized 作用于办法时,办法的拜访标识会有ACC_SYNCHRONIZED 示意该办法须要加锁

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

Java 中的 synchronized 默认是可重入锁

  • 当线程要拜访须要加锁的对象时 (执行 monitorentry)
  1. 先查看对象头中加锁次数,如果为 0 阐明未加锁,获取后,加锁次数自增
  2. 如果不为 0,再查看获取锁的线程是不是本人,如果是本人就能够拜访,加锁次数自增
  3. 如果不为 0 且获取锁线程不是本人,就阻塞

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

为什么会有 2 个 monitorexit ?

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

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

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

总结

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

办法调用指令分为动态、公有、接口、虚、动静办法等,返回指令则次要是以 i、l、f、d、a 结尾的 return 指令别离解决不同类型的返回值

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

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

异样解决指令用于抛出异样,革除操作数栈并将异样压入调用者操作数栈顶

同步控制指令常应用 monitorentrymonitoryexit,为了避免异样时死锁,抛异样前执行monitoryexit

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

本篇文章笔记以及案例被支出 gitee-StudyJava、github-StudyJava 感兴趣的同学能够 stat 下继续关注喔 \~

有什么问题能够在评论区交换,如果感觉菜菜写的不错,能够点赞、关注、珍藏反对一下 \~

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

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

正文完
 0