【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

这篇具有很好参考价值的文章主要介绍了【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

JVM系列整体栏目


内容 链接地址
【一】初识虚拟机与java虚拟机 https://blog.csdn.net/zhenghuishengq/article/details/129544460
【二】jvm的类加载子系统以及jclasslib的基本使用 https://blog.csdn.net/zhenghuishengq/article/details/129610963
【三】运行时私有区域之虚拟机栈、程序计数器、本地方法栈 https://blog.csdn.net/zhenghuishengq/article/details/129684076
【四】运行时数据区共享区域之堆、逃逸分析 https://blog.csdn.net/zhenghuishengq/article/details/129796509
【五】运行时数据区共享区域之方法区、常量池 https://blog.csdn.net/zhenghuishengq/article/details/129958466
【六】对象实例化、内存布局和访问定位 https://blog.csdn.net/zhenghuishengq/article/details/130057210
【七】执行引擎,解释器、JIT即时编译器 https://blog.csdn.net/zhenghuishengq/article/details/130088553

一,深入理解执行引擎

1,执行引擎的概述

在JVM整个体系中,执行引擎属于第三层,主要用来执行具体的字节码文件。本文主要探讨的就是这个执行引擎。
【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

执行引擎是Java虚拟机核心组成的一部分,“虚拟机” 是一个相对于 “物理机” 的一个概念,这两种机器都有执行代码的能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统的层面上的,而虚拟机的执行引擎是由软件自行实现的,因此可以不受物理条件制约的指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的格式。java虚拟机可以理解成一个抽象的计算机,相较于真正的物理机而言,java虚拟机的执行效率会略慢于物理机。

JVM的主要任务是负责装载字节码到其内部,但字节码并不能够直接运行在操作系统上面,因为字节码指令并非等价于本地机器指令,他内部包含的仅仅是一些能够被JVM识别的字节码指令等信息。如下图所示,这些字节码指令不能直接在操作系统上解释执行,而是需要现通过jvm虚拟机来执行这些字节码指令。

【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

因此,执行引擎的主要作用就是:将字节码指令解释成或者编译成对应平台上面的本地机器指令 ,简单的来说,JVM中的执行引擎充当了将高级语言翻译成机器语言的翻译者

执行引擎在执行过程中,其需要的具体的字节码指令完全依赖于程序计数器,每当完成一项操作指令之后,程序计数器就会更新下一条需要被执行的指令地址。在方法的执行全过程中,执行引擎有可能会通过存储在局部变量表的对象引用准确的的获取存储在Java堆中的对象实例信息,以及通过对象头中的元数据指针定位到目标对象的类型信息。

2,Java代码编译和执行的过程

大部分的程序代码在转换成物理机的目标代码或者虚拟机能执行的指令集之前,都需要经历过几下几个步骤

【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

🧢 前面的黄线流程代表的就是将 .java 文件编译成 .class 文件,属于是前端编译;

🧢 绿色部分属于解释器解释执行的过程,即逐行翻译、解释、执行的过程;

🧢 蓝色部分属于是JIT即时编译器编译性阶段,属于是后端编译。

2.1,解释器和编译器

解释器:当Java虚拟机启动的时候,会根据预定义的规范对字节码采用逐行解释的方式执行,将每条字节码文件中的内容翻译成对应平台的本地机器指令

JIT编译器:jit,又名Just In Time Compiler , 就是直接将源代码编译成和本地平台相关的机器语言。

在java语言中,是既可以通过解释器来执行代码,也可以通过编译器来执行代码的,这二者都可以达到相同的目的,并且这二者以合作的方式相辅相成,取长补短,以最合适的方法让Java内部执行的效率更高。JVM虚拟机不仅仅是针对于Java语言,只要遵循Jvm虚拟机规范的语言,都可以使用JVM虚拟机解释执行。

【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

如上图,将不同的语言通过统一处理,生成对应的字节码文件,然后通过虚拟机中的解释器或者JIT即时编译器对这些字节码进行解释执行,然后翻译成对应的字节码指令,最后将这些指令全部存储在方法区的CodeCache中。

2.2,机器码、指令、汇编语言、高级语言

1,机器码

各种用二进制编码方式表示的指令,叫做 机器指令码 ,如通过01010101 这种二进制的方式进行编码,最开始人们就用它编写程序,这就是 机器语言。机器语言虽然可以被计算机接收,但是和人们的语言差别太大,不易被人家理解和记忆,用它变成也容易出错。用它编写的程序,一经输入计算机,CPU直接读取运行,因此和其他语言的程序,执行速度最快。机器指令和CPU紧密相关,因此不同类型的CPU所对应的机器指令也就不同。

2,指令

由于机器码是由0和1的二进制组成,可读性实在是太差,于是人们发明了指令。指令就是把机器码特定的 0和1 序列,简化成了对应的指令,如mov和inc等,可读性好。但是由于不同的硬件平台,执行同一个操作,其对应的字节码可能会不同,所以不同硬件平台的同一种指令,对应的机器码也可能不同。在不同的硬件平台,各自支持各自的指令,每个平台所支持的指令总和,称之为对应平台的 指令集

3,汇编语言

又由于指令的可读性差,于是又发明了这个汇编语言。在汇编语言中,用助记符代替机器指令的操作码,用地址符号代替指令或者操作数的地址。在不同的硬件平台,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令,由于计算机只认识指令码,所以用汇编语言编写的程序还必须翻译成机器指令码,计算机才能识别。

4,高级语言

高级语言比上述语言接近人的语言,如当今流行的c或者c++,当计算机执行高级语言的时候,仍然需要把程序解释或者编译成机器指令码,完成这个过程的程序就叫做解释程序或者编译程序。因此不管是汇编语言还是这个高级语言,都需要最终生成这个机器指令,然后将这个机器指令放在CPU上面操作,最终解释执行。

【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

字节码属于是一种中间状态的二进制代码,他比机器码更加抽象,需要直译器转译后才能成为机器码,与硬件环境无关,可以直接通过编译器或者虚拟机器,将源码编译成字节码。

2.3,解释器和编译器工作机制(重点)

解释器真正意义上所承担的角色就是一个 “运行时的翻译者”,就是将字节码中的内容翻译成对应平台的本地机器指令执行。每当一条字节指令被解释执行完成后,接着再根据 程序计数器 中记录的下一条需要被执行的字节码指令执行解释操作。

在JVM平台中,也对解释器进行了优化,采用了一种JIT 的即时编译的技术,目的是避免函数被解释执行,而是将整个函数体编译成机器码,每次函数执行时,只执行编译后的编译码即可,这种方式大大的提升了执行效率。

在hotspot虚拟机中,JIT即时编译器的速度远快于解释器,并且将字节码指令直接生成机器指令,存储在这个方法区的CodeCache中缓存起来,比这个解释器逐行翻译的效率高很多。因此在今天,Java程序的运行性能早以脱胎换骨,已经可以达到和c/c++程序一较高下的地步。

但是即使这个jit即时编译器的速度很快,在HotSpot虚拟机中,依旧保留了这个解释器,原因是JIT即时编译器虽然效率很高,但是需要一定的时间编译成机器码,才能继续工作。但是这个编译器在程序启动之后,可以立马进行工作,省去编译的时间,立即执行。

所以综上两点,在程序启动的时候JIT需要编译,那么就由解释器来执行程序,待JIT即时编译器编译成机器码之后,再由这个JIT即时编译器来完成,这样就能让整个执行引擎发挥最大的效率。因此二者合作共存才能让效率最大化。

2.4,JIT编译器的热点代码和热点探测

Java语言的编译器其实是一段不太确定的操作过程,因为他可能是一指前端编译器(编译器的前端,.java文件编译成 .class文件)的过程,也可能是指后端的编译器(JIT编译器,将字节码转换成机器码)的过程,还有可能是指静态提前编译器,直接把 .java 文件编译成本地机器代码的过程。

在使用这个JIT编译器的时候,需要判断代码被调用执行的频率,对于需要被编译为本地代码的字节码,被称为热点代码 ,JIT编译器在运行时对那些频繁被调用的热点代码会做出深度优化,将其直接编译为对应平台的本地机器指令,以提升Java程序的执行性能。

热点代码 :指的是一个被多次调用的方法,或者是一个方法体内部循环次数较多的循环体,都可以被称为"热点代码"。因此可以通过JIT编译器译为本地机器指令,由于这种编译方式发生在方法的执行过程中,因此也被称为栈上替换。

热点探测方式:而是否可以成为这个热点代码,主要是依靠这个热点探测功能,HotSpot虚拟机主要采用的热点探测方式是基于计数器的热点探测。HotSpot虚拟机又将每个方法建立两个不同类型的计数器,分别是方法调用计数器和回边计数器,方法调用计数器用于统计方法的调用次数,回边计数器用于统计循环体的执行次数。

2.5,方法调用计数器和回边计数器

在JIT的热点探测中,主要是通过计数器的方式来实现对代码的探测,计数器主要分为方法调用计数器和回边计数器。

2.5.1,方法调用计数器

这个计数器主要用于统计方法被调用的次数,它的默认阈值在Client模式下是1500次,在Server模式下是10000次,超过这个阈值,就会触发JIT编译。这个阈值也可以通过虚拟机参数 -XX:CompileThreshold进行设置。当一个方法被调用的时候,会先检查这个方法是否存在被JIT编译过的版本,如果存在,则优先使用编译后的本地代码来执行,如果不存在,则将此方法的调用计数器值加1,然后判断 方法调用计数器和回边计数器 值的和是否超过方法调用计数器的阈值,如果已经超过阈值,那么将会向即时编译器提交一个该方法的代码编译请求。

【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

如上图所示,在调用方法时,会先判断该代码是否已经编译,如果已经编译,则直接通过这个JIT即时编译器将机器码生成对应的本地机器码指令;如果未编译,则将方法调用计数器加1,随后回去判断是否超过阈值,如果超过阈值,则会提交编译请求,通过JIT即时编译器进行动态编译,然后将编译后的机器指令缓存在CodeCache中,如果未超过阈值,那么继续通过解释器解释执行。

在JVM内部对调用的次数也做了一定的限制,并不是说一直对调用的次数进行类加,而是在一段时间内记录方法调用的次数,当超过一定的时间限度,如果方法调用的次数依旧没有达到这个阈值,那么方法的调用计数器就会进行一个 衰减 的过程,每次衰减一半,这段衰减的过程被称为方法统计的 半衰周期

进行衰减的动作是虚拟机在垃圾收集的时候顺便进行的,可以使用虚拟机参数 -XX:-UseCounterDecay 来关闭或者开启热度衰减,因此只要系统运行的时间足够长,那么绝大多数的方法都会编译成本地代码。同时也可以通过参数 -XX:CounterHalfLifeTime 设置半衰周期的时间,单位是s

2.5.2,回边计数器

主要是统计一个方法中的循环体的执行次数,在字节码中遇到流控流向后跳转的指令称为 “回边” 。

【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

和方法调用计数器一样,会先判断一下该代码是否已经编译,如果未编译,则回边计数器的值加1,然后去判断将当前累加的值和方法调用计数器的值进行累加是否超过阈值,如果超过,则使用JIT编译器,否则依旧使用解释器执行。

2.6,编译器和解释器设置

上述可知在HotSpot虚拟机中存在解释器和编译器,如通过以下命令可以得知,当前虚拟机采用的是一种混合的方式共同执行程序。

java -version

【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

除了这种之外,也可以通过显式的命令为Java虚拟机指定只由其中一种执行程序,如可以通过以下这个命令设置只使用解释器执行程序

java -Xint -version

【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

或者可以通过以下命令只设置使用编译器来执行程序,但是如果编译出现问题,解释器会接入执行

java -Xcomp -version

【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

当然上面这两种需要在特殊的场景下使用,需要变回混合使用

java -Xmixed -version

【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

除了可以通过这个命令行设置之外,也可以通过这个虚拟机参数就行设置,其代码如下,通过虚拟机的不同参数设置,可以得到以下答案,纯解释需要花8666ms,纯编译只需要花2ms,混合使用也是1-2ms,因此选择这个混合是最佳的,同时也可以知道使用这个纯编译器的时间远远小于这个纯解释型。

/**
 *
 * -Xint : 8666ms
 * -Xcomp:2ms
 * -Xmixed: 2ms
 * @author zhenghuisheng
 * @date : 2023/4/11
 */
public class C {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        test();
        long end = System.currentTimeMillis();
        System.out.println((end - start) + "ms");
    }

    public static void test(){
        int k = 0;
        for (int i = 0; i < 1000000; i++) {
            for (int j = 0; j < 1000; j++) {
                k = i + j;
            }
        }
    }
}

在虚拟机设置那里修改对应的参数即可。

【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

而在HotSpot虚拟机中内嵌有两个JIT的编译器,分别是Client Compiler和Server Compiler,但是在绝大多数的情况下,这两个编译器被称为C1编译器和C2编译器。
🧢 -client :运行在Client模式下,对字节码进行可靠和简单的优化,耗时短
🧢 -server:运行在Server模式下,对字节码进行耗时长的优化、激进优化,效率更高

C1编译器的优化策略主要有:方法内联、去虚拟化、冗余消除
C2编译器的优化策略主要有:标量替换、栈上分配、同步消除文章来源地址https://www.toymoban.com/news/detail-427227.html

到了这里,关于【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入理解JVM虚拟机第二篇:虚拟机概念和JVM整体架构以及字节码的执行路线

      😉😉 学习交流群: ✅✅1:这是孙哥suns给大家的福利! ✨✨2:我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 🥭🥭3:QQ群:583783824   📚📚  工作微信:BigTreeJava 拉你进微信群,免费领取! 🍎🍎4:本文章内容出自上述:Spring应用课程!💞💞

    2024年02月09日
    浏览(46)
  • 【jvm系列-06】深入理解对象的实例化、内存布局和访问定位

    JVM系列整体栏目 内容 链接地址 【一】初识虚拟机与java虚拟机 https://blog.csdn.net/zhenghuishengq/article/details/129544460 【二】jvm的类加载子系统以及jclasslib的基本使用 https://blog.csdn.net/zhenghuishengq/article/details/129610963 【三】运行时私有区域之虚拟机栈、程序计数器、本地方法栈 https

    2023年04月16日
    浏览(48)
  • 【Python编程系列】2、Python解释器

    当我们使用\\\"Install Now\\\"的默认安装方式时,会自动安装一个纯Python下使用Tkinter编写的相当基本的IDE。 什么是IDE?Integrated Development Environment,集成开发环境。 有多基础呢?可以打开看看它的界面就知道了! 编写代码后,点击回车键即可执行代码。 我们一般不会使用自带的ID

    2024年02月12日
    浏览(31)
  • 【Python系列】Python 解释器的站点配置

    💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老 导航 檀越剑指大厂系列:全面总

    2024年04月08日
    浏览(38)
  • 软件设计模式系列之十七——解释器模式

    解释器模式是一种行为型设计模式,它用于将一种语言或表达式解释为对象。该模式通过定义语言的文法规则,并使用解释器来解释和执行这些规则,将复杂的语言转换为对象的操作。 在软件开发中,解释器模式常用于处理类似于编程语言、查询语言、正则表达式等需要解释

    2024年02月08日
    浏览(24)
  • 破解小程序禁止使用JS解释器动态执行JS(eval5、estime、evil-eval等)代码的终极解决方案

    关于被小程序禁止使用eval函数的问题,大家都多少了解了,新规则已经限制死了。请看下面新规则。 既然要求如此严格,那么有没有其它解决方案呢,所谓上有正常,下有对策。故今天这篇文章就是要提供新的思路实现动态执行js代码的方案。 云函数 云对象 是的,既然在代

    2024年02月10日
    浏览(75)
  • 【JVM】JVM之执行引擎

    本文我们将讲解JVM中的执行引擎。 问题:我们平时所写的Java程序是如何将其进行编译并转换为计算机能够识别的机器码呢?并且Java程序编译和C/C++程序编译有什么区别呢?我们所说的JIT编译器和平时说的编译器有什么区别呢?…我相信在阅读本文过后,你会有一个清楚的认

    2023年04月21日
    浏览(36)
  • JVM的执行引擎

    执行引擎属于 JVM 的下层,包括 解释器、即时编译器、垃圾回收器 ,是Java虚拟机核心的组成部分之一。 用二进制编码方式表示的指令,叫做机器指令码。 用机器码编写的程序一经输入计算机,CPU 直接读取运行,因此和其他语言编的程序相比,执行速度最快。 机器指令与

    2024年02月01日
    浏览(30)
  • JVM 执行引擎

    javac 编译器将 Java 代码编译成 class 文件 (前期编译),再给 JVM 根据不同平台 , 通过执行引擎转为机器码 JVM 用 : 混合模式 (解释+编译) : 对不常用代码,不浪费时间编译成机器码,用时以解释运行 对热点代码,用编译方式,追求更高效率 Interpreter : 将字节码逐条换成机器码 刚

    2024年02月11日
    浏览(35)
  • JVM核心原理解读(一)---执行引擎

    Java虚拟机规范制定了Java字节码执行引擎的概念模型,Java执行引擎作用概括起来就是执行编译产生的Java class文件,为用户提供了底层OS的调用,屏蔽了不同平台硬件和OS的差异性,使得编写的代码无差别的在各个平台运行;对于Java字节码执行一般有解释执行和编译执行两种,具体使用

    2024年02月11日
    浏览(72)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包