Please enable JavaScript.
Coggle requires JavaScript to display documents.
字节码执行引擎 - Coggle Diagram
字节码执行引擎
运行时栈帧结构
局部变量表
操作数栈
动态连接
-
- 每一个栈帧中都包含一个执行运行时常量池中该栈帧所属方法的调用
- 栈的最大深度在编译时写到Code属性的max_stacks变量中
- 操作数栈中的元素的数据类型必须与字节码指令的序列严格匹配,数据类型也要相同
- 两个虚拟机栈帧可能出现重叠 即下面栈帧的操作数栈和上面栈帧的局部变量表重叠,用于方法调用时可以直接复制变量
- 基于栈的执行引擎即为操作数栈
- 一组变量值的存储空间
- 存放方法参数和方法内部定义的局部变量
- 以变量槽为基本单位,32字节的数据结构一个变量槽,64子节点的两个变量槽
- 局部变量表第一个参数为this
- 如果当前字节码PC计数器的值已经超过某个变量作用域,对应的变量槽可以交给其他变量重用,垃圾回收的问题
- 局部变量不存在准备阶段,即不存在初始化零值 定义时需要先赋值
方法调用
确定被调用方法的版本
解析
- 类加载的解析阶段会将其中的一部分符号引用转化为直接引用,调用目标在程序代码写好,编译的时候已经确定下来,这类方法调用被称为解析
- invokestatic 用于调用静态方法
- invokespecial 用于调用实例构造器<init>() 方法,私有和父类中方法
- invokevirtual 调用所有的虚方法
- inovkeinterface 调用接口方法,在运行时再确定一个实现该接口的对象
- invokedynamic 运行时动态解析出调用点限定符所引用的方法,然后再执行该方法,分派逻辑用户实现
非虚方法
- invokestatic、invokespecial 指令调用的方法可以在编译时确定唯一的版本,这些方法有:静态方法,私有方法、实例构造器
父类方法
- 被final修饰的方法
- 以上方法被叫做非虚方法,除此之外都是虚方法
- 没有虚的字段,只有虚的方法
分派
静态分派
- 重载
- Human human = new Man() Human 为静态类型,Man为实际类型
- 静态类型在编译期可知,实际类型到运行期可知
- 虚拟机在重载时通过参数的静态类型而不是实际类型作为判断依据
- 依赖静态类型进行方法执行版本的分派动作叫做静态分派
动态分派
- 重写
- 对于虚方法使用invokevirtual指令该指令会做以下事:
- 找到操作数栈顶的第一个元素所指向的对象的实际类型 叫做C
- 如果C中包含该方法且能访问返回方法的直接引用否则递归向上查找
- 如果找不到则报错
- 根据方法接收者的实际类型来选择方法版本
- 这种在运行期根据实际类型确定方法版本的叫做动态分派
- 子类的同名字段会遮蔽父类字段的值
动态分派的实现
- 为类型在方法区实现一个虚方法表
- 使用虚方法表索引替代元数据查找提高性能
- 如果方法没有被重写则父子类种相同方法的入口地址是相同的
- 如果发生重写则子类虚方法表种址将被替换成子类实现的方法入口地址
- 具有相同签名的方法,在父子类的虚方法表种索引相同
- 虚方法表在类加载的连接阶段进行初始化
- java对象中方法默认就是虚方法除了final
单分派与多分派
- 方法的接收者与方法参数统称为方法的宗量
- 根据分派基于多少种宗量可以分为单分派和多分派
- JAVA是一种静态多分派,动态单分派的语言
- var是根据右侧数据类型进行静态推断数据结构的,是语法糖
动态语言类型支持
- 动态类型检查的主体过程在运行期而不是编译期
- Java会在编译期间将每个类的方法完整的符号引用生成出来并作为方法调用指令的参数,存储到class文件中
- 该符号引用包括方法定义在哪个类,方法的名字,参数顺序,参数类型,返回值
java.lang.invoke 包
- JDK7 提供了一个新的动态确定目标方法的机制,称为方法句柄
- 通过使用MethodHandle 进行手动分派可指定方法版本
- 实际上模拟了invokevirtual 指令的执行
与Reflection的区别
- Reflection是在java代码层次,MethodHandle是在字节码层次的调用
- Reflection重量级包含了方法的全量信息,MH是轻量级的
- MH可以通过虚拟机优化调用
- MH可以用于其他语言非java
invokedynamic
- 每一处含有invokedynamic指令的位置都被称为动态调用点
- 这条指令的第一个参数不是代表方法符号引用的CONSTANT_Methodref_info常量,而是CONSTANT_InvokeDynamic_info常量
- 该常量包括:引导方法,方法类型,方法名称
- 引导方法是固定参数返回值为CallSite对象,最终调用到要执行的目标方法上