深入分析JVM执行引擎

程序和机器沟通的桥梁

一、闲聊

相信很多朋友在出国旅游,或者与外国友人沟通的过程中,都会遇到语言不通的烦恼。这时候我们就需要掌握对应的外语或者拥有一部翻译机。而笔者只会中文,所以需要借助一部翻译器才能与不懂中文的外国友人交流。咱们的执行引擎就类似于这部”翻译机”。

二、概述

执行引擎的作用就是将字节码指令解释或者编译为对应平台上的本地机器指令。简单来说,执行引擎充当了将高级语言翻译为机器语言的翻译者。对于Hotspot虚拟机,执行引擎中包含两部分:解释器和JIT编译器(即时编译器)。下图是执行引擎的原理:

深入分析JVM执行引擎

三、解释器

解释器所承担的角色就是一个运行时 翻译者,将字节码文件中的内容 翻译为对应平台的本地机器码指令。当一条字节码指令被解释执行后,接着再根据pc寄存器中记录的下一条需要被执行的字节码指令执行解释操作。JVM解释器一共有两套,一套是远古的 字节码解释器,另一套是现在普遍使用的 模板解释器

1、字节码解释器

字节码解释器在执行过程中通过 纯软件代码模拟字节码执行,效率非常低。

2、模板解释器

模板解释器将 每一条字节码和一个模板函数关联,模板函数中直接产生这条字节码指令执行时的机器码,从而提高了解释器的性能。在常用的HotSpot VM中,解释器主要由Interpreter模板和code模块构成。Interpreter模板:实现了解释器的核心功能。code模块:用于管理HotSpot VM在运行时生成的本地机器码指令。

四、即时编译器(JIT编译器)

即时编译器的目的是避免函数被解释执行,而是将整个函数体编译成机器码指令,每次函数执行时,只执行编译后的机器码即可,这种方式可以大大的提高效率。

1、热点代码及探测方式

当然,是否需要JIT编译器将字节码直接编译成对应平台的机器码,需要根据代码被调用的 执行频率而定。需要被JIT编译器编译成机器码的字节码,也称为 热点代码,JIT编译器会对热点代码做出 深度优化,将其从字节码编译成机器码, 并缓存到方法区,提高代码的执行效率。
JIT编译的方式发生在方法执行过程中,因此也被称之为_栈上替换_,或简称OSR(On Stack Replacement)编译。通过 热点探测的方法,判断一个方法被调用多少次,或循环体执行多少次才可以达到阈值,进行编译。而Hotspot VM热点探测的方式是基于计数器实现的。这种基于技术的热点探测方式又分为两种:1.方法调用计数器 2.回边计数器

关于栈上替换这里笔者不展开赘述,有兴趣的小伙伴可以自行了解下

1.1方法调用计数器

方法调用计数器用于统计方法调用次数,它的默认阈值是client模式下是1500次,在server模式下是10000次。超过这个阈值,就会触发JIT编译。当然,这个阈值也可以通过修改虚拟机参数 -XX:CompileThreshold来手动指定。
当一个方法被调用的时候,会优先检查该方法是否被JIT编译过,如果存在,则优先使用编译过的本地代码来执行,如果不存在,则将此方法的调用计数器加一,然后再判断计数器的值是否超过配置的阈值。如果已经超过了,就会向JIT编译器提交一个该方法的编译请求。下面是方法调用计数器执行的流程图:

深入分析JVM执行引擎
关于方法调用计数器,如果不做任何设置,方法调用计数器统计的并不是方法被调用的绝对次数,而是一个相对执行的频率。当超过一定的时间限度,如果方法的调用次数仍然达不到阈值,那这个方法的调用计数器就会被减少一半,这个过程称为方法调用计数器的 热度衰减,而这段时间被称作为该方法的 半衰周期
进行热度衰减的过程是虚拟机进行垃圾回收的时候顺便进行的,举手之劳而已。可以使用虚拟机参数 -XX:-UseCounterDecay来关闭热度衰减。这样的话,只要运行时间足够长,绝大部分方法都会被编译成本地代码。最后,还可以使用 -XX:CounterHalfLifeTime参数设置半衰周期的时间,单位为秒。

1.2回边计数器

它的作用是统计一个方法中 循环体代码执行次数,在字节码中遇到控制流向后,跳转的指令称为”回边”。显然,建立回边计数器统计的目的是为了触发OSR编译。下面是回边计数器执行的流程图:

关于OSR编译上文中有提到

深入分析JVM执行引擎

2、即时编译器分类

在Hotspot VM中,内嵌有两个JIT编译器,分别为client compiler和server compiler,但是大多数情况下我们简称C1编译器和C2编译器。可以通过命令显示的指定JVM在运行时到底使用哪种JIT编译器。

2.1 c1编译器

指定Java虚拟机运行在client模式下,使用C1编译器。C1编译器会对字节码进行简单和可靠的优化,耗时短。以达到更快的编译速度,但是编译后的代码执行速度相对慢。C1编译器主要有方法内联,去虚拟化,冗余消除。

  1. 方法内联:将引用的函数代码编译到引用点处,这样可以减少栈帧的生成,减少参数传递以及跳转过程。
  2. 去虚拟化:对唯一实现的类进行内联。
  3. 冗余消除:在运行期间把一些不会执行的代码叠掉。

2.2 c2编译器

指定Java虚拟机运行在server模式下,使用C2编译器。C2编译器对代码优化时间长,编译时间也长。但是编译后的代码执行速度比较快。C2的优化主要在全局层面,逃逸分析式优化的基础。基于逃逸分析,C2上有如下几种优化:

  1. 标量替换:用标量值代替聚合对象的属性值。
  2. 栈上分配:对于未逃逸的对象分配在栈上而不是堆上。
  3. 同步消除:清楚同步操作,通常指synchronized。

2.3 Graal编译器

JDK10起,在C1编译器和C2编译器之后,HotSpot VM新增了一个Graal即时编译器。编译效果短短几年的时间就追平了C2编译器。目前,带着”实验状态”标签,需要使用开关参数 -XX:+UnlockExperimentalVMOptions-XX:+UseJVMCICompiler去激活这个编译器,才能使用。

五、解释器和JIT并存

为什么需要解释器和JIT并存,原因有几点:

  1. 当程序启动的时候,解释器可以马上发挥作用,省去编译的时间。
  2. 编译器想要执行,需要把字节码编译成本地机器码,并且缓存编译后的机器码,编译需要一定的时间。
  3. 编译后的本地机器码,执行效率高。所以,在两种并存的模式下,解释器首先发挥作用,而不必等到即时编译器全部编译完在执行,这样可以省去不必要的编译时间。
  4. 随着程序继续不断运行,编译器发挥作用,根据 热点探测功能,把越来越多的字节码编译成本地机器码,获得更高的执行效率。

六、执行引擎执行程序的方式

在默认的情况下,HotSpot VM采用的是解释器和JIT编译器并存的架构,当然读者可以根据具体的应用场景,通过虚拟机参数,为虚拟机指定在运行时到底是完全采用解释器执行,还是完全采用即时编译器执行。

  1. -Xint:完全采用解释器模式执行程序
  2. -XComp:完全采用即时编译器模式执行程序。如果即时编译器出现问题,解释器会介入执行;
  3. -Xmixed:采用解释器+即时编译器的混合模式共同执行程序,HotStop VM默认就是这个模式。

Original: https://www.cnblogs.com/cicada-smile/p/16633767.html
Author: 知了一笑
Title: 深入分析JVM执行引擎

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/610708/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • DHCP服务

    一、dhcp介绍 dhcp 应用层协议 动态主机配置协议 作用: 为主机动态分配tcp/ip参数(ip地址、掩码、网关、DNS服务器地址) Linux实现dhcp服务 软件: dh…

    Linux 2023年6月7日
    085
  • 【考研】C语言

    考研C语言 收录数据结构会用到的C语言知识,建议有基础的情况下再学习,针对性学习即可。 往后的学习要多从内存角度去学习计算机的知识 1. 数组 1.1 一维数值数组 具备相同的数据…

    Linux 2023年6月13日
    0110
  • 【原创】Linux PCI驱动框架分析(二)

    背 景 Read the fucking source code! –By 鲁迅 A picture is worth a thousand words. &#8211…

    Linux 2023年6月8日
    0105
  • Redis之延迟监控

    *参考官方文档 *启用 redis 延迟监控 CONFIG SET latency-monitor-threshold 100 单位:毫秒,100表示一百毫秒。如果将 latenc…

    Linux 2023年5月28日
    096
  • Linux系统编程 —线程同步概念

    同步概念 同步,指对在一个系统中所发生的事件之间进行协调,在时间上出现一致性与统一化的现象。 但是,对于不同行业,对于同步的理解略有不同。比如:设备同步,是指在两个设备之间规定一个…

    Linux 2023年6月14日
    096
  • Netty-如何写一个Http服务器

    前言 动机 最近在学习Netty框架,发现Netty是支持Http协议的。加上以前看过Spring-MVC的源码,就想着二者能不能结合一下,整一个简易的web框架(PS:其实不是整…

    Linux 2023年6月7日
    098
  • mysql update语句的执行流程是怎样的

    update更新语句流程是怎么样的 update更新语句基本流程也会查询select流程一样,都会走一遍。 update涉及更新数据,会对行加dml写锁,这个DML读锁是互斥的。其…

    Linux 2023年6月8日
    098
  • Django补充

    django配置文件相关操作 django实际上有两个配置文件 一个是提供给用户可以自定义的基本配置 from 项目名 import settings 一个是全局的系统默认的配置 …

    Linux 2023年6月7日
    0105
  • CentOS——Redis远程连接可视化工具Rdis Desktop Manage

    前排提示 Centos没有安装Redis的可参考 https://www.cnblogs.com/tianhengblogs/p/15265028.html 一。 修改redis….

    Linux 2023年5月28日
    0168
  • js中对象深度拷贝的方法(浅拷贝)

    JS中,一般的赋值传递的都是对象/数组的引用,并没有真正的深拷贝一个对象(浅拷贝),某些情况下需要用到深度拷贝,可以使用如下写法 let data = {username:&quo…

    Linux 2023年6月14日
    0100
  • 洛谷P3372–线段树代码模板1

    时空限制:1000ms,128M 数据规模: 对于30%的数据:N Original: https://www.cnblogs.com/ygsworld/p/11279732.ht…

    Linux 2023年6月7日
    0120
  • 操作系统实现-进入内核

    博客网址:www.shicoder.top微信:18223081347欢迎加群聊天 :452380935 这一次我们正式进入内核,编写相关的内核代码,也就是kernel代码 数据类…

    Linux 2023年6月13日
    0102
  • Identity Server 4使用OpenID Connect添加用户身份验证(三)

    一、说明 基于上一篇文章中的代码进行继续延伸,只需要小小的改动即可,不明白的地方可以先看看本人上一篇文章及源码: Identity Server 4资源拥有者密码认证控制访问API…

    Linux 2023年6月13日
    083
  • 3.21 Linux PATH环境变量及作用(初学者必读)

    在讲解 PATH 环境变量之前,首先介绍一下 which 命令,它用于查找某个命令所在的绝对路径。例如: [root@localhost ~]# which rm /bin/rm …

    Linux 2023年6月7日
    087
  • VRRP配置即实验

    VRRP 概念: VRRP 全称是虚拟路由器冗余协议,它是一种容错协议。该协议通过把几台路由设备联合组成一台虚拟的路由设备,该虚拟路由器在本地局域网拥有唯一的一个虚拟ID和虚拟IP…

    Linux 2023年6月6日
    083
  • 操作系统实战45讲- 02 几行汇编几行C:实现一个最简单的内核

    本节源代码位置https://gitee.com/lmos/cosmos/tree/master/lesson02/HelloOS Hello OS 之前,我们先要搞清楚 Hell…

    Linux 2023年6月7日
    094
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球