首页 > 其他分享 >JVM(九)执行引擎

JVM(九)执行引擎

时间:2023-07-12 10:46:52浏览次数:25  
标签:解释器 字节 编译 编译器 引擎 JVM 执行 机器指令

JVM(九)执行引擎


1 执行引擎概述

  • 执行引擎是Java虚拟机核心的组成部分之一

  • 虚拟机是一个相对于物理机的概念,这两种机器都有代码执行能力,区别在于物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的,而虚拟机的执行引擎是由软件自主实现的,因此可以不受物理条件制约地定制指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式

  • JVM的主要任务是负责装载字节码到其内部,但字节码并不能直接运行在操作系统之上,因为字节码并不等价于机器指令,其内部仅包含一些能够被JVM识别的字节码指令、符号表以及其他的一些辅助信息

  • 为了能让Java程序执行起来,执行引擎的任务就是将字节码指令解释、编译为对应平台上的本地机器指令。即JVM执行引擎充当着将高级语言翻译为机器语言的翻译者。

    image-20230601201825771

2 执行引擎的工作过程

  • 执行引擎在执行过程中执行什么字节码指令取决于PC寄存器
  • 每当执行引擎执行完一条字节码指令后,PC寄存器就会更新下一条需要执行的字节码指令的地址
  • 方法在执行的过程中,执行引擎可能会通过存储在局部变量表中的对象引用准确定位到Java对中的实例对象,或者通过对象头元数据指针定位到方法区中的对应类型信息
  • 栈帧的的操作数栈是执行引擎的主要工作区Java虚拟机的解释引擎就是基于栈的执行引擎,这里的栈就是指的操作数栈
  • 当一个方法开始执行的时候,一个新的栈帧就会被创建出来;执行引擎根据PC寄存器存储的字节码地址解释成机器指令执行,方法结束的时候如果被调用的方法带有返回值的话,返回值将会被压入当前栈帧的操作数栈中,并更新PC寄存器中下一条需要执行的字节码指令
image-20230601202853661

3 Java代码编译和执行的过程

机器码、指令、汇编语言
  • 机器码用二进制编码方式表示的指令,输入计算机后CPU能够直接运行读取,因此执行速度最快,并且机器指令与CPU密切相关,不同种类的CPU对应的机器指令也不同
  • 指令由于机器码是0和1的二进制序列可读性太差,所以使用指令替代特定的0、1序列,如movinc等;不同硬件平台的机器码也有可能不同
  • 汇编语言使用助记符代替机器指令的操作码,用地址符号或者标号代替指令或者操作数的地址;汇编语言必须翻译成机器指令码,计算机才能够识别运行
  • 高级语言必须翻译成汇编语言,然后才能被翻译成机器指令
image-20230605141108610
字节码
  • 字节码是一种中间状态(中间码)的二进制代码,它比机器指令更加抽象,需要直译器转译之后才能成为机器码
  • 字节码主要是为了实现特定软件运行和软件环境,与硬件无关
  • 字节码的实现方式是通过编译器虚拟机器编译器将源码编译成字节码,特定平台上的虚拟机器将字节码转译成可以直接执行的指令
image-20230605142007506
1 解释器
  • 解释器的工作主要是在运行的时候将字节码中的内容翻译成对应平台的机器指令执行

  • 当一条字节码被解释执行完成之后,接着再根据PC寄存器中记录的下一条需要被执行的字节码指令执行解释操作

  • 解释器主要有两种:

    • 字节码解释器:通过纯软件代码模拟字节码的执行,效率比较低下
    • 模板解释器将每一条字节码和一个模板函数相关联,模板函数会直接产生这条字节码执行时的机器码,从很大程度上提高了解释器的性能,也是现在普遍使用的解释执行器
  • HotSpot虚拟机中,解释器主要由Interpreter模块和Code模块构成

    • Interpreter模块:实现了解释器的核心功能
    • Code模块:用于管理HotSpot虚拟机在运行时生成的本地机器指令
  • 基于解释器的执行方式已经成为了低效的代名词,因此JVM支持一种即时编译技术即将整个函数体翻译成机器码避免对函数进行翻译,并将其缓存,之后每次函数执行时只执行编译后的字节码即可

2 JIT编译器
  • Java语言的JIT即时编译器指的是虚拟机的后端运行期编译器会将字节码转变成机器码
  • 此外还有前端编译器,会把.java源程序转变成机器码
  • 静态提前编译器直接把.java文件编译成本地机器代码
image-20230605162530943

​ 上图的绿色和蓝色路径分别对应下图的两种Java代码执行方式:

image-20230605162604082
  • 第一种是通过将源代码编译成字节码文件,然后在运行时由解释器将字节码文件逐行编译编译成机器码执行

  • 第二种是直接编译执行,采用即时编译技术(Just In Time)直接编译成机器码

  • HotSpot采用解释器和JIT并行的架构:

    • 当程序启动后解释器可以马上发挥作用,省去编译的时间,立即能够执行
    • 而即时编译器想要发挥作用,就需要先将代码编译成本地机器指令,编译需要一定的时间,但完成之后执行效率比逐行解释执行效率更高

    这么做的原因主要是当JVM启动的时候,解释器可以首先发挥作用,而不必等待即时编译器全部编译完成之后再执行,这样可以省去许多不必要的编译时间,但随着时间的推移,编译器发挥作用将越来越多的代码翻译成本地代码,能够获得更高的执行效率

3 热点代码探测,确定何时JIT即时编译
  • 是否需要启动JIT编译器字节码直接翻译为对应平台的机器码,需要根据被调用代码的执行频率而定

  • 需要被翻译成本地代码的字节码被称作热点代码,一个被多次调用的方法,或者方法内部多次执行的循环体,都可以被称作热点代码

  • JIT编译器会在运行时针对频繁被调用的热点代码进行深度优化,将其直接编译成对应平台的本地机器指令,以提高Java程序的执行性能,由于这种编译方式放生在栈上,因此也被称作是栈上替换,或简称OSR(On Stack Replacement)编译

  • HotSpot VM 目前采用的是基于计数器的热点探测,虚拟机会为每一个方法都建立两种不同类型的计数器,分别为方法调用计数器回边计数器

    • 方法调用计数器用于统计方法的调用次数,它的默认阈值在Client模式下是1500次,在Server模式下是10000次,超过就会触发JIT编译,可以通过参数设定:

      -XX:CompileThreshold
      
    • 回边计数器用于统计循环体的执行次数

  • 当一个方法被调用的时候,会先检查该方法是否存在被JIT编译过的版本,如果存在,则优化使用编译后的本地代码来执行,如果不存在则直接将方法调用计数器+1,并检查计数是否超过阈值,没有超过则以解释的方式逐行解释执行字节码指令,超过阈值则向即时编译器提交一个该方法的代码编译请求,将整个方法在后台编译为本地方法并缓存到方法区

    image-20230605185223423
4 热度衰减

​ 如果不做任何设置,方法调用计数器统计的并不是方法被调用的绝对次数,而是一个相对的执行频率,即一段时间之内方法被调用的次数。当超过一定的时间限度,如果方法的调用次数仍然不足以让它提交给即时编译器编译,那这个方法的调用计数器就会被减少一半,这个过程称为方法调用计数器热度的衰减(Counter Decay),而这段时间就称为此方法统计的半衰周期(Counter Half Life Time)(半衰周期是化学中的概念,比如出土的文物通过查看C60来获得文物的年龄)

​ 进行热度衰减的动作是在虚拟机进行垃圾收集时顺便进行的,可以使用虚拟机参数 -XX:-UseCounterDecay 来关闭热度衰减,让方法计数器统计方法调用的绝对次数,这样的话,只要系统运行时间足够长,绝大部分方法都会被编译成本地代码。

​ 另外,可以使用-XX:CounterHalfLifeTime参数设置半衰周期的时间,单位是秒。

5 HotSpot VM可以设置程序执行的方式

​ 缺省情况下,HotSpot VM采用解释器与即时编译器并存的架构,开发人员也可以根据具体的应用场景,通过命令显式地指定JVM在运行时完全采用解释器执行还是完全采用即时编译器执行。

image-20230606161320079
  • -Xint:完全采用解释器模式执行程序
  • -Xcomp:完全采用即时编译器模式执行程序,如果即时编译器出现问题,解释器就会介入
  • -Xmixed:采用解释器+即时编译器混合模式共同执行程序

JIT分类:

​ HotSpot Vm中内嵌了两个JIT编译器,分别为Client CompilerServer Compiler,又被称作C1编译器和C2编译器,可以使用命令-client-server显式指定在运行时使用哪一种即时编译器:

  • Client Compiler

    • C1编译器会对字节码进行简单和可靠的优化耗时短,以达到更快的编译速度

    • C1编译器方法计数器的阈值为1500次

    • C1编译器上的主要优化策略有方法优化去虚拟化冗余消除

      image-20230606162418779
  • Server Compiler

    • C2编译器会进行耗时较长的优化,以及激进优化,但优化的代码执行效率更高

    • C2编译器方法计数器的阈值为10000次

    • C2编译器的优化主要是在全局层面,基于逃逸分析有如下几种优化:

      image-20230606162518082

4 Graal编译器和AOT编译器

标签:解释器,字节,编译,编译器,引擎,JVM,执行,机器指令
From: https://www.cnblogs.com/tod4/p/17546897.html

相关文章

  • JVM(十三)分代收集、增量收集以及分区算法
    JVM(十三)分代收集、增量收集以及分区算法1分代收集算法​ 前面的所有算法中,没有一种算法能够完全替代其他算法,它们都有自己独特的优势和特点,分代收集算法应运而生:分代收集算法对不同生命周期的对象采取不同的收集方式,一般划分为新生代和老年代,以便提高回收效率在Java程序......
  • JVM(十二)垃圾清除阶段算法
    JVM(十二)垃圾清除阶段算法垃圾清除阶段是指,当成功区分出内存区域中的存活对象和死亡对象之后,GC接下来的任务就是执行垃圾回收,释放掉无用对象所占用的内存空间,以便有足够的可用内存空间为新对象分配内存。目前在JVM中比较常见的三种垃圾收集算法是标记-清除算法(Mark-Sweep)......
  • JVM(十一)垃圾回收概述和垃圾标记阶段的算法
    JVM(十一)垃圾回收概述和垃圾标记阶段的算法1Java垃圾回收概述什么是垃圾?垃圾是在程序运行过程中不被任何指针指向的对象,这个对象就是需要被回收的垃圾为什么要进行垃圾回收?如果不及时对内存中的垃圾进行清理,那么这些垃圾对象所占内存空间会一直保存到应用程序结束,被......
  • 初识虚拟机JVM
    初识JVM(JAVAVirtualMachine)​ JVM是一种规范,可以使用软件来实现,也可以使用硬件来实现,就是一个虚拟的用于执行bytecodes字节码的计算机。他也定义了指令集、寄存器集、结构栈、垃圾收集堆、内存区域。​ JVM负责将java字节码解释运行,边解释边运行,这样,速度就会受到一定的影......
  • 【Netty】「源码解析」(三)设置连接超时:深入分析 ChannelFuture.sync() 的执行过程
    前言本篇博文是《从0到1学习Netty》中源码系列的第三篇博文,主要内容是深入分析连接超时的实现原理,包括了connect方法的源码解析和ChannelFuture.sync()执行过程的解析。,往期系列文章请访问博主的Netty专栏,博文中的所有代码全部收集在博主的GitHub仓库中;介绍在实际应用中,当......
  • 数据库存储引擎介绍
    存储引擎输入:showengines;#查看MySQL中的储存引擎有哪些MySQL总共支持9种存储引擎,主要需要了解的有3种:1.MyISAM: 它是MySQL5.5及之前的版本默认的存储引擎,它的存取速度更快,但是数据相对InnoDB不够安全 使用该引擎产生三个文件 .frm:这个文件存表结构 .MYD:......
  • mybatisPlus 中设置批量更新执行耗时
    设置myBatisPlus中使用批量更新执行的时间耗时短在连接mysql的url后添加&rewriteBatchedStatements=true为什么默认不给这个rewriteBatchedStatements属性设置为true,原来有如下原因:看下executeBatchedInserts究竟干了什么:如果批量语句中的某些语句失败,则默认重......
  • 针对表的SQL语句、针对记录的SQL语句、存储引擎、数据类型、创建表的完成语法
    针对表的SQL语句有表的前提是先有库什么是表?表相当于文件,表中的一条记录就相当于文件的一行内容,不同的是,表中的一条记录有对应的标题,称为表的字段selectdatabase();查看当前所在库use  库名;使用库1.查看表showtables;查看那所有表showcreatetable t......
  • 北京汽车牵手火山引擎数智平台,探寻车企数字化升级新通路
    “北京汽车正在为车企数字化升级跑出一条新通路。” 汽车行业的竞争向来激烈,随着数字化浪潮的持续推进,特别是一大批互联网背景的人物和企业入场,各大车企加速在数据智能应用上发力,以打破如今“用户越来越懂车,但车企却越来越难懂用户”的市场僵局。 作为国内领先的车企之一,北......
  • JVM(六)堆
    JVM(六)堆1核心概述几乎所有的对象实例和数组都是分配在堆上的(栈不会存储数组和对象,栈帧中的局部变量表只会存储指向堆中实例的引用)一个Java进程对应一个JVM实例,一个JVM实例只存在一个堆内存,堆也是内存管理的核心区域堆和方法区是线程共享的,但堆也有划分的线程私有缓冲区......