JVM-11. 虚拟机字节码执行引擎
1 运行时栈帧
- 栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构。
- 位于虚拟机运行时数据区中的虚拟机栈(Virtual Machine Stack)中的栈元素。
- 存储了方法的局部变量,操作数栈,动态链接和方法返回地址,额外附加信息
- 一个方法的调用和执行完成,对应着一个栈帧在虚拟机栈里面入栈到出栈的过程
- 当前栈帧(Current Stack Frame):栈顶的有效栈帧,与这个栈帧相关联的方法为当前方法(Current Method)。执行引擎运行的所有字节码指令都只针对当前栈帧操作。
1.1 局部变量表
- 局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内部的局部变量
- 编译期在方法的Code属性的max_locals数据项中确定了方法所需要分配的局部变量表的最大容量
- 局部变量表的最小单位是变量槽(Variable Slot),简称Slot
- 方法执行时,虚拟机是使用局部变量表来完成参数值到参数变量列表的传递的:
实例方法的局部变量表第0位索引的slot默认是用于传递方法所属对象实例的引用,方法中使用关键字this访问这个隐含的参数。其余参数占位从1开始的局部变量slot
1.2 操作数栈
- 操作数栈(Operand Stack) 也被称为操作数栈,是一个后入先出(LIFO)栈。
- 最大深度在编译时写入到Code属性的max_stacks数据项中
- 操作数栈中的元素是任意的Java数据类型
- 操作数栈中的元素数据类型必须和字节码指令的序列严格匹配
- 虚拟机可能对栈帧作出一些共享,让下面栈帧的操作数栈帧和上面栈帧的部分局部变量表重合,从而共用部分数据
1.3 动态链接
- 栈帧包含一个运行时常量池中改帧所属方法的引用
- 目的是为了支持方法调用过程中的动态链接(Dynamic Linking)
1.4 方法返回地址
- 方法开始执行后,两种方法退出:
- 执行引擎遇到任意一个方法返回的字节码指令,此时可能有返回值传递给上层方法调用者,被称为正常完成出口(Normal Method Invocation Completion)
- 在方法执行过程中遇到异常,并且异常没有在方法体内得到处理,被称为异常完成出口(Abrupt Method Invocation Completion),这种方法退出不会传递给上层调用者任何返回值
- 方法退出过程实际上等同于把当前栈帧出栈
1.5 附加信息
- JVM规范允许JVM增加一下额外信息到栈帧中,例如调试相关的信息
2. 方法调用
方法调用不等于方法执行,调用的唯一任务是确定调用方法的版本。
2.1 解析
- 方法调用的目标方法在Class文件中是一个常量池的中的符号引用
- 类加载阶段,一部分符号引用转化为直接引用,前提条件是:方法在程序真正运行之前就有一个可确定的调用版本,且在运行期不可变。
- 这类方法的调用称为“解析(Resolution)”
- 主要有静态方法和私有方法两大类,前者与类型直接关联,后者在外部不可被访问。因此他们都不可能通过继承或者其他方式重写为其他版本
- 解析过程一定是一个静态过程,在编译期间就完全确定
2.2 分派
分派实现了多态性特征的最基本的体现。
2.2.1 静态分派
静态分派和方法重载有很密切的联系。
- 静态类型(Static Type)外观类型(Apparent Type)和实际类型(Actual Type)在程序中都有可能发生一些变化,区别是静态类型的变化仅仅在使用时发生,变量本身的静态类型不会被改变,且最终的静态类型在编译器可知;实际类型的变化结果在运行时才可确定。
- 重载时通过参数的静态类型而不是实际类型作为判断依据。
- 所有依赖静态类型来定位方法执行版本的分派动作成为静态分派。例如方法重载。
- 静态分派发生在编译阶段。
- 字面量不需要定义,所以字面量没有显示的静态类型,只能通过语言上的规则理解和推断。产生了重载方法的匹配优先级。
2.2.2 动态分派
动态分派和方法重写有很密切的联系。
- 在运行期间根据实际类型确定方法执行版本的分派过程成为动态分派。
- 依据invokevirtual指令实现,吧常量池中的类方法符号引用解析到了不同的直接引用上。
2.2.3 单分派与多分派
- 方法的接受者与方法的参数统称为方法的宗量。
- 根据分派基于多少中宗量,可以将分派划分成单分派和多分派两种:
- 单分派是根据一个宗量对目标方法进行选择
- 多分派是根据多个宗量对目标方法进行选择。
- Java静态分派属于多分派类型
- Java动态分派属于单分配类型
2.3 动态类型语言支持
- 动态语言的类型检查的主体过程是在运行期而不是编译期
- java.lang.invoke包提供MethodHandle的机制提供动态确定目标方法的机制
- invokedynamic指令