目录
1. 概述
- 物理机的执行引擎是直接建立在处理器、硬件、指令集和操作系统层面的。
- 虚拟机执行引擎是有自己实现的。可以自行制定指令集与执行引擎的结构体系,并能够个执行那些不被硬件直接支持的指令集格式。
2.运行时栈帧结构
- 栈帧:用于虚拟机进行方法调用和方法执行的数据结构。是JVM运行时数据区虚拟机栈的栈元素。
- 执行引擎运行的所有字节码指令指针相对当前栈帧进行操作。
2.1 局部变量表
- 最大容量有Code属性的的max_locals数据项确定。
- java语言中明确的64为数据类型只有long和double两种。
- 局部变量表中的slot是重用的。(当PC计数器超过某个变量的作用域时,那个变量对应的Slot就可以交给其他的变量使用)
2.2 操作数栈
- 64位数据的栈容量为2
- java虚拟机的解释执行引擎成为“基于栈的执行引擎”
2.3 动态连接
- 静态解析
一些符号引用在类加载阶段或者第一次使用的时候就直接转化为直接引用
- 动态连接
另一部分在每一次运行期间转化为直接引用.
2.4 方法返回地址
2.5 附加信息
与调试相关的信息等。
3.方法调用
唯一的任务是缺少被调用方法的版本。
3.1 解析
“编译器可知,运行期不可变”的方法:
- 静态方法
- 私有方法
在解析阶段能确定唯一的调用版本(只要能被invokestatic和invokespecial指令调用的方法):成为非虚方法
- 静态方法
- 私有方法
- 实例构造器
- 父类方法
3.2 分派
实际类型和静态类型:
Human man = new Man();
- 其中<Human>称为静态类型,也叫外观类型。
- Man称为实际类型。
- 区别在于静态类型的变化只在使用时发生,变量本身的静态类型不会被改变,最终的将他类型实在编译期可知的;实际类型变化的结果运行期才可确定
分派:
3.2.1 静态分派
- 典型应用:方法重载
- 发生在编译阶段
- 编译器很多情况下怎能确定一个“更加合适”的重载版本
- 自动类型转化:char--int--long--float--double
3.2.2 动态分派
- 重要体现:方法重写
- 在于内心期间根据实际类型确定方法执行版本的分派
3.2.3 单分派与多分派
宗量:方法的接收者和方法的参数。
- 单分派:根据一个宗量对目标方法进行选择
- 多分派:根据多于一个宗量对目标方法进行选择
java静态分派为多分派类型。
java动态分派为单分派类型。
3.2.4 虚拟机动态分派实现
稳定优化手段:虚方法表
使用虚方法表索引来代替元数据查找以提高性能。
激进优化手段:
- 内联缓存
- 基于“类型继承关系分析CHA”的守护内联
3.3 动态类型语言支持
4.基于栈的字节码解释执行引擎
4.1 解释执行
javac编译请完成的编译动作是在java虚拟机紫外进行的,而解释器实在虚拟机内部,多亿Java程序的编译是半独立的实现。
4.2 基于栈的指令集与基于寄存器的指令集
基于栈的指令集优点:
- 可移植
- 代码更加紧凑(每个字节码对应一个指令)
- 编译器实现更加简单(不考虑空间分配问题,所需空间在栈上操作)
缺点:
- 执行慢:出栈和入栈操作等。频繁的内存访问:相对于处理器而言,内存时总是执行速度的瓶颈。