深入理解Java虚拟机6-chap8-9-斗者3星

时间:2023-03-10 05:35:46
深入理解Java虚拟机6-chap8-9-斗者3星

一、虚拟机字节码执行引擎

  1.虚拟机执行引擎由自己实现,所以可以自行制定指令集与执行引擎的体系结构,并且可以执行那些不被硬件直接支持的指令集格式。

  2.执行引擎

  • 编译执行:通过JIT编译器产生本地代码执行
  • 解释执行:通过解释器解释执行

二、运行时栈帧结构

  • 栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每一个方法从调用开始至执行完成的过程,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。
  • 对于执行引擎来说,在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧。

  深入理解Java虚拟机6-chap8-9-斗者3星

  1.局部变量表

  • 编译时,在方法的Code属性的max_locals确定需要分配的局部变量表的最大容量
  • 对于实例方法,局部变量表中的0位索引的Slot默认记录方法所属对象实例的引用,即this指针
  • 根据变量作用域,Slot可以被复用,可能对垃圾回收产生影响,如果对变量赋null,在JIT编译中会被清除,最优雅的解决方法是以恰当的变量作用域来控制变量的回收时间

  2.操作数栈

  • LIFO栈
  • 最大深度为编译时写入方法表中Code属性的max_stacks
  • 可能会有不同栈间的数据共享  

  深入理解Java虚拟机6-chap8-9-斗者3星

  3.动态连接

  • 每个栈帧都包含一个指向运行时常量池中该栈帧所属性方法的引用,用来支持动态连接
  • 字节码中的方法调用指令:以常量池中指向方法的符号引用为参数
  • 符号引用解析:一部分发生在类加载或者第一次使用,即静态解析,动态解析发生在每一次运行期

  4.方法返回地址

  • 正常完成出口
  • 异常完成出口

  5.附加信息

  • 在实际开发中,一般会把动态连接,方法返回地址与其它附加信息全部归为一类,称为栈帧信息。

三、方法调用

  • 目的:确定调用方法的版本
  • 一切方法调用在Class文件里存储的都只是符号引用,而不是方法在实际运行时内存布局中的入口地址(相当于直接引用)

  1.解析

  • 类加载的解析阶段,会把其中一部分符号引用转化为直接引用,前提:方法在程序运行之前只有一个可确定的调用版本,并且这个调用版本在运行期不可变
  • 编译器可知,运行期不可变:静态方法与私有方法,
  • 五条方法调用字节码指令

  1)invokestatic:调用静态方法

  2)invokespecial:调用实例构造器方法,私有方法和父类方法。

  3)invokevirtual:调用虚方法。

  4)invokeinterface:调用接口方法,会在运行时再确定一个实现此接口的对象。

  5)invokedynamic:先在运行时动态解析出调用点限定符所引用的方法,然后再执行该方法,在此之前的4条调用指令,分派逻辑是固化在Java虚拟机内部的,而invokedynamic指令的分派逻辑是由用户所设定的引导方法决定的。

  • 只要能被invokestatic与invokespecial指令调用的方法,都可以在解析阶段确定唯一的调用版本,符合这个条件的有静态方法,私有方法,实例构造器和父类方法四类,它们在类加载的时候就会把符号引用解析为该方法的直接引用。这些方法可以统称为非虚方法,与之相反,其它方法就称为虚方法(除去final方法)。
  • final方法虽然由invokevirtual调用,但是由于它无法被覆盖,没有其他版本,所以也是非虚方法

  2.分派

  • 静态分派:依赖静态类型来定位方法执行版本的分派动作称为静态分派,典型应用为方法重载

  1)Shape s = new Circle(),Shape称为静态类型,Circle称为实际类型

  • 动态分派:依赖动态类型执行方法分派,典型应用为重写

  1)动态分派时,会根据当前栈帧的局部变量表,进行挨个遍历匹配接受者(即调用者),由于invokevirtual指令执行的第一步就是在运行期确定接受者的实际类型,这个过程就是Java语言重写的本质

  • 单分派与多分派

  1)方法的接受者与方法的参数称为方法的宗量。

  2)单分派是根据一个宗亮对目标方法进行选择,多分派是根据多个宗量

  3)Java语言:静态多分派、动态单分派

  4)动态分派,优化手段:虚方法表,若方法没被重写,则地址入口与父类相同方法地址一致

  深入理解Java虚拟机6-chap8-9-斗者3星

  3.动态语言支持

  • 反射与invokedynamic指令

四、基于栈的字节码解释执行引擎

  1.解释执行

  • Java 语言中, Javac 编译器完成了程序代码经过词法分析、语法分析到抽象语法树,再遍历语法树生成线性的字节码指令流的过程
  • 解释器在JVM内部,所以Java程序的编译是半独立的实现

  深入理解Java虚拟机6-chap8-9-斗者3星

  • 中间过程:解释执行
  • 下面过程:传统编译原理程序代码到目标机器代码的生成过程

  2.基于栈指令集与寄存器指令集

  • 基于栈的指令集主要的优点就是可移植,寄存器由硬件直接提供,程序直接依赖这些硬件寄存器则不可避免地要受到硬件的约束。
  • 栈架构指令集的主要缺点是执行速度相对来说会稍慢一些。
  • 虽然栈架构指令集的代码非常紧凑,但是完成相同功能所需的指令数量一般会比寄存器架构多,因为出栈、入栈操作本身就产生了相当多的指令数量,,栈实现在内存之中,频繁的栈访问也就意味着频繁的内存访问,相对于处理器来说,内存始终是执行速度的瓶颈。

五、类加载器

  1.Tomcat

  深入理解Java虚拟机6-chap8-9-斗者3星

  2.OSGI:运行时生成类加载体系结构

  3.字节码生成与动态代理技术

  4.Restrotranslator:Java逆向移植工具

  • 基本原理是将新特性在编译时进行替换,如包装对象,更换为Integer.valueOf()

参考:

  https://gavinzhang1.gitbooks.io/java-jvm-us/content/xu_ni_ji_zi_jie_ma_zhi_xing_yin_qing.html