1.概述
在不同的虚拟机实现里面,执行引擎在执行Java代码的时候可能会有解释执行(通过解释器执行)和编译执行(通过即时编译器产生本地代码执行)两种选择
2..运行时栈帧结构
栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈(Virtual Machine Stack)的栈元素。
栈帧包括了局部变量表、操作数栈、动态连接、方法返回地址和一些额外的附加信息。
3.方法调用
方法调用阶段唯一的任务就是确定被调用方法的版本(即调用哪一个方法)。
所有方法调用中的目标方法在Class文件里面都是一个常量池中的符号引用,在类加载的解析阶段,会将其中的一部分符号引用转化为直接引用
方法在程序真正运行之前就有一个可确定的调用版本,并且这个方法的调用版本在运行期是不可改变的。
3.1 解析
调用目标在程序代码写好、编译器进行编译时就必须确定下来。这类方法的调用称为解析(Resolution)
解析调用一定是个静态的过程,在编译期间就完全确定,在类装载的解析阶段就会把涉及的符号引用全部转变为可确定的直接引用,不会延迟到运行期再去完成。
Java虚拟机里面提供了5条方法调用字节码指令:
- invokestatic:调用静态方法。
- invokespecial:调用实例构造器<init>方法、私有方法和父类方法。
- invokevirtual:调用所有的虚方法。
- invokeinterface:调用接口方法,会在运行时再确定一个实现此接口的对象。
- invokedynamic:先在运行时动态解析出调用点限定符所引用的方法,然后再执行该方法,
3.2 分派
分派(Dispatch)调用可能是静态的也可能是动态的
- 静态分派
- 动态分派
根据分派依据的宗量数 可分为单分派和多分派
- 单分派
- 多分派
4.基于栈的字节码解释执行引擎
4.1 编译过程
Java语言中,Javac编译器完成了程序代码经过词法分析、语法分析到抽象语法树,再遍历语法树生成线性的字节码指令流的过程。
4.2 基于栈的指令集与基于寄存器的指令集
- 基于栈的指令集:指令流中的指令大部分都是零地址指令,它们依赖操作数栈进行工作
- 基于寄存器的指令集:最典型的就是x86的二地址指令集,说得通俗一些,就是现在我们主流PC机中直接支持的指令集架构,这些指令依赖寄存器进行工作。
4.3 基于栈的解释器执行过程
栈结构指令集的一般运行过程,整个运算过程的中间变量都以操作数栈的出栈、入栈为信息交换途径
ps:这一节看的有点乏味,只了解了下大致的概念,后续有空再继续深入看下。
声明:本文是个人学习笔记,内容来自《深入理解Java虚拟机·JVM高级特性与最佳实践》周志明 与网络文章