# 五、字节码执行引擎

# 1. 概述

# 1.1 功能

  • JVM 的字节码执行引擎的基本功能就是输入字节码文件,然后对字节码进行解析并处理,最后输出执行的结果。

# 1.2 实现方式

①通过编译器直接解释执行字节码 —— 读一句 -> 解释一句 -> 执行一句

② 通过即时编译器产生本地代码(编译执行)—— 先整体编译成机器码 -> 直接执行机器码

③ 上述两种结合

# 2. 栈帧

image-20210305143923925
  • 栈帧是用于支持 JVM 进行方法调用方法执行的数据结构。
  • 栈帧随着方法调用而创建,随着方法结束而销毁。
  • 栈帧里面存储了:
    • 方法的局部变量
    • 操作数栈
    • 动态连接
    • 方法返回地址
    • ....

# 2.1 局部变量表

用来存放方法参数和方法内部定义的局部变量的存储空间。

  1. 以变量槽 slot 为单位,目前一个 slot 存放 32 位以内的数据类型。

  2. 对于 64 位数据(如 long、double)占 2 个 slot。

  3. 对于实例方法,第 0 位 slot 存放的是 this,然后从 1 到 n,依次分配给参数列表和局部变量。

    //实例方法
    public int add(int a, int b){
        int c = a + b;
        return a + b + c;
        
        //slot 排位
        //0--this
        //1--a
        //2--b
        //3--c
    }
    

    使用 javap -verbose 反汇编后得到的结果如下:

    image-20210305145735854
  4. 对于静态方法,就没有 this 了

    //静态方法
    public static int staticAdd(int a,int b){
        int c = a + b;
        return a + b + c;
        
        //slot 排位
        //0--a
        //1--b
        //2--c
    }
    
    image-20210305150026578
  5. slot 是复用的,以节省栈帧的空间,这种设计可能会影响到系统的垃圾回收行为。所以当确定引用不会再被使用的时候,最好是显式将其置为 null

    public static void main(String[] args) {
    
        //定义一个 2M 的数组
        {
            byte[] bs = new byte[2 * 1024 * 1024];
        }
    
        //出了作用域后,bs 已经没用了,但是它的插槽仍然存在:slot排位
        //0--args
        //1--bs1
    
        int a = 0;
        //加入 int a=0 后,为了节省栈帧的空间,slot 进行复用,所以 1 号 slot 就分给了 a
    
        //slot排位
        //0--args
        //1--a
    
        //并不保证 gc 一定会触发
        System.gc();
    }
    

# 2.2 操作数栈

用来存放方法运行期间,各个指令操作的数据。

  1. 操作数栈中元素的数据类型必须和字节码指令的顺序严格匹配。
  2. 虚拟机在实现栈帧的时候可能会做一些优化,让两个栈帧出现部分重叠区域,以存放公用的数据。

# 2.3 动态链接

每个栈帧都有一个指向运行时常量池中该栈帧所属方法的引用,以支持方法调用过程的动态链接。

  1. 静态解析:类加载的时候,符号引用就转化为直接引用。
  2. 动态链接:运行期间转换为直接引用。

# 2.4 方法返回地址

方法执行后返回的地址(方法被调用的地方)。

# 2.5 方法调用

确定具体调用哪一个方法,并不涉及方法内部的执行过程(只是一个找的过程,并不会执行方法)。

  1. 部分方法是直接在类加载的解析阶段,就确定了引用关系。如静态方法、私有方法、实例构造器、父类方法。
  2. 但是对于实例方法,也称虚方法,因为重载和多态,需要运行期间动态委派。

# 2.6 分派

# 静态分派

所有依赖静态类型来定位方法执行版本的分派方式。

如:重载方法(看参数列表的数据类型)

# 动态分派

根据运行期的实际类型来定位方法执行版本的分派方式。

如:覆盖方法

上次更新: 8/27/2021, 6:21:27 PM