执行引擎,是Java虚拟机最核心的组成部分之一,执行引擎在执行代码时可能是编译执行,也可能是解释执行,也可能两者兼备。但所有的执行引擎都是输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果
1. 运行时栈帧结构
栈帧,是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈的栈元素。栈帧储存了局部变量表,操作数栈,动态链接和方法返回地址等信息
- 编译期就已经确定了栈帧的局部变量表的大小和操作数栈的深度
- 当前栈帧:对于执行引擎来讲,活动线程中,只有栈顶的栈帧是有效的
- 当前方法:当前栈帧关联的方法
1.1 局部变量表
变量值存储空间,用于存放方法参数和方法内部定义的局部变量
- 以变量槽(Slot)为最小单位
- 使用局部变量表完成参数值到参数变量列表的传递过程的
- 如果是实例方法,局部变量表的第0位索引的Slot默认是用于传递方法所属对象实例的引用
- 一个局部变量可以保存一个类型为boolean、byte、char、short、int、float、reference和returnAddress类型的数据
- 如果Slot是32位的,则遇到一个64位数据类型的变量(如long或double型),则会连续使用两个连续的Slot来存储。
- Slot的复用
java栈之局部变量表
1.2 操作数栈
- 最大深度在code属性中的
max_stack
数据项中 - 一开始操作数栈是空的,在方法执行过程中,会有各种字节码指令向操作数栈写入和提取内容
- 概念模型中,操作数栈是相互独立的,但实际上的栈帧会出现一部分重叠,这样在调用时就可以共用一部分数据
- “基于栈的执行引擎”,其中的栈就是操作数栈
1.3 动态链接
每个栈帧都包含一个指向运行时常量池中该栈帧索树方法的引用,持有这个引用是为了支持方法调用过程中的动态连接
- 常量池中存在大量的符号引用,这些符号引用一部分会在类加载阶段或第一次使用时转化为直接引用,称为静态解析,还有一部分在运行期间转化为直接引用,称为动态解析
1.4 方法返回地址
退出可能的操作:
- 恢复上层方法的局部变量表和操作数栈
- 把返回值压入调用者栈帧的操作数栈中
- 调整PC计数器的值以指向方法调用指令后面的一条指令等
1.5 附加信息
2. 方法调用
方法调用不等同于方法执行,它的唯一任务就是确定被调用方法的版本,不涉及运行过程
- Class文件的编译过程不涉及传统编译过程的连接步骤,一切方法调用在CLass文件里面存储的都只是符号引用,而不是直接引用,这个特性给Java带来了很强的动态扩展能力
2.1 解析
- 特点:是静态过程;在编译期间就完全确定,在类装载的解析阶段就会把涉及的符号引用全部转变为可确定的直接引用,而不会延迟到运行期再去完成,即编译期可知、运行期不可变
- 适用对象:静态方法(与类型直接关联)、私有方法(在外部不可被访问),它们都不可能通过继承或其他方式重写其他版本
2.2 分派
- 静态分派:依赖静态类型来定位方法的执行版本;典型应用是方法重载;发生在编译阶段,不由Java虚拟机来执行
- 动态分派:依赖动态类型来定位方法的执行版本;典型应用是方法重写;发生在运行阶段,由Java虚拟机来执行
- 单分派:根据一个宗量对目标方法进行选择(方法的接受者与方法的参数统称为方法的宗量)
- 多分派:根据多于一个宗量对目标方法进行选择
网友评论