虚拟机字节码执行引擎

﹏ヽ暗。殇╰゛Y 2023-02-16 06:18 323阅读 0赞

不同虚拟机实现中,执行引擎在执行字节码得时候通常会有解释执行和编译执行两种选择,也可能两者兼具,还有可能同时包含几个不同级别得即使编译器一起工作得执行引擎,但是所有 Java 虚拟机得执行引擎输入,输出都是一致得:输入的是字节码二进制流,处理过程是字节码解释执行的等效过程,输出的是执行结果;

一、运行时栈帧结构

java 虚拟机以方法作为最基本的执行单元,栈帧则是支持虚拟机进行方法调用和方法执行背后的数据结构,它也是虚拟机运行时数据区域中虚拟机栈的栈元素,每一个栈帧都包括了局部变量操作数栈动态连接方法返回地址和一些额外的附加信息

栈帧的概念结构:
在这里插入图片描述

(1)局部变量表

局部变量表是一组变量值的存储空间,用于存放方法的参数和方法内部定义的局部变量,以变量槽为最小单位,每个变量槽都应该能存放一个 boolean , byte , char , short , int , floate , reference , returnAddress 类型的数据;

(2)操作数栈

操作数栈也常被称为操作栈,它是一个先进先出栈,操作数栈的最大深度在编译的时候被写入Code 属性的 max_stacks 数据项中,当一个方法开始执行时,操作数栈是空的,在方法执行的过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是入栈和出栈操作。两个不同的栈帧作为不同虚拟机的虚拟机栈的元素,是完全独立的,但是大多数情况下会让下面栈帧的部分操作数栈与上面栈帧的部分局部变量表重叠在一起,节约了空间,在方法调用时直接公用一部分数据,无需额外的参数复制传递;

两个栈帧之间的数据共享:
在这里插入图片描述

(3)动态连接

每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。 Class 文加的常量池中有大量的符号引用,字节码中的方法调用指令就是以常量池中指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或者第一次使用的时候就被转化为直接引用,这种转化被称为静态解析。另外一部分将在每一次运行期间转化为直接引用,这部分就称为动态连接

(4)方法返回地址

方法退出的两种方式:

  • 正常调用完成 :执行引擎遇到任意一个方法返回的字节码指令,这时候可能会有返回值传递给上层的方法调用者,方法是否有返回值以及返回值的类型将根据方法返回指令来决定;
  • 异常调用完成 :在方法执行过程中遇到了异常,并且这个异常不能再方法中解决

无论以何种方式退出,都必须返回到最初方法被调用的位置,程序才能执行。
方法正常退出时:主调方法的 PC 计数器的值就可以作为返回地址,栈帧中很可能或保存这个计数器值。
方法异常退出时:返回地址是要通过异常处理器来确定的,栈帧中一般不会保存这个信息。

(5)附加信息

虚拟机可以增加一些规范里没有描述的信息到栈帧中,例如:调试,性能收集相关的信息。一般情况会把动态连接,方法返回地址与其他附加信息全部归为一类称为栈帧信息

二、方法调用

方法调用不等同于方法中的代码被执行,它的作用是确定被调用方法的版本Class 文件的编译过程中不包含传统语言编译的链接步骤,一切方法调用再 Class 文加里面存储的都只是符号引用,而不是方法在实际运行时内存布局中的入口地址;

(1)解析

调用目标在程序代码写好,编译器进行编译的那一刻就已经确定下来了,这类方法的调用被称为解析

Java 虚拟机支持以下五种方法调用字节码指令:

  • invokestatic :用于调用静态方法;
  • invokespecial :用于调用实例构造器 < init >( ) 方法,私有方法和父类方法;
  • involeirtual:用于调用所有虚方法;
  • invokeinterface :用于调用接口方法;
  • invokedynamic :先在运行时动态解析出调用点限定符所引用得方法,然后再执行方法;

前面 4 条指令,分派逻辑都固化在Java虚拟机内部,而invokedynamic 指令得分派逻辑都是由用户设定得引导方法来决定的;

(1)分派

静态分配:所有依赖静态类型来决定方法和执行版本的分派动作都称为静态分配,最典型的表现就是方法重载,并且发生在编译阶段;

动态分配:它最经典的表现就是重写;

单分配:根据一个宗量对目标方法进行选择(方法的接收者和方法的参数统称为方法的宗量)

多分配:根据多余一个宗量对目标方法进行选择;

三、动态类型语言支持
(1)动态类型语言

动态类型语言:关键特征是它的检查类型的主体过程是否在运行期而不是编译期。动态类型语言包括:JavaScript,Lua,Python,Groovy,APL,Clojure,Erlang,Lisp,Prolog,Smalltake,Lisp

(2)Java 与动态类型

不仅仅是Java语言,别的语言也可以运行在Java虚拟机之上,例如:Clojure,Groovy,Jython 和 JRuby;

(3)java.lang.invoke包

该包的主要目的:在之前单纯依靠符号引用来确定调用的目标方法这条路之外,提供一条新的动态确定目标方法的机制,称为方法句柄

(4)invokedynamic指令

该指令为了解决指令方法分派规则完全固化在虚拟机中的问题,把如何查找目标方法的决定权从虚拟机转嫁到用户代码中,让用户有更高的自由度;每一处含有 invokedynamic 指令的位置都被称为动态调用点

发表评论

表情:
评论列表 (有 0 条评论,323人围观)

还没有评论,来说两句吧...

相关阅读

    相关 虚拟字节执行引擎

    > 不同虚拟机实现中,执行引擎在执行字节码得时候通常会有解释执行和编译执行两种选择,也可能两者兼具,还有可能同时包含几个不同级别得即使编译器一起工作得执行引擎,但是所有 Jav

    相关 虚拟字节执行引擎

    在前面的几篇文章里,从Java虚拟机内存结构开始,经历了虚拟机垃圾收集机制、Class类文件结构到后来的虚拟机类加载机制,一步步的进入到了Java虚拟机即Java底层的世界。在

    相关 JVM—虚拟字节执行引擎

    执行引擎是Java虚拟机最为核心的组成部分之一. 虚拟机是一个相对于物理机的概念, 两种及其都有代码执行能力, 其区别是物理机的执行引擎是直接建立在处理器, 硬件, 指令集和操