JVM即时编译(JIT)

JVM基础回顾

Java 作为一门高级程序语言,由于它自身的语言特性,它并非直接在硬件上运行,而是通过编译器(前端编译器)将 Java 程序转换成该虚拟机所能识别的指令序列,也就是字节码,然后运行在虚拟机之上的;JVM的存在主要

  • 提供了可移植性,一旦 Java 代码被编译为 Java 字节码,便可以在不同平台上的 Java 虚拟机实现上运行,选择在虚拟机上实现就可以避免在硬件上实现的高成本
  • 提供了一个代码托管的环境,代替我们处理部分冗长而且容易出错的事务,例如内存管理。以及在这个运行时的环境里可以加入垃圾回收,类型检查,安全权限等功能,使开发人员免于书写无关业务逻辑的代码,提升开发效率

那么我们知道从硬件视角来看,Java 字节码无法直接执行。因此,Java 虚拟机需要将字节码翻译成机器码。这里也是java与一些静态编译语言的不同。

在 HotSpot 里面,上述翻译过程有两种形式:第一种是解释执行,即逐条将字节码翻译成机器码并执行;第二种是即时编译(Just-In-Time compilation,JIT),即将一个方法中包含的所有字节码编译成机器码后再执行。

前者的优势在于启动速度快,无需等待编译,无额外内存占用;而后者的优势在于实际运行速度更快,程序启动后,编译器逐渐发挥作用,把越来越多的热点代码优化编译保存成成本地代码,可以减少解释器的中间消耗,提高执行效率。

HotSpot 默认采用混合模式,综合了解释执行和即时编译两者的优点。它会先解释执行字节码,而后将其中反复执行的热点代码,以方法为单位进行即时编译。

Hot Spot即时编译器

为了满足不同用户场景的需要,HotSpot 内置了多个即时编译器:C1、C2 和 Graal(Java 10 引入的实验性即时编译器)。

C1 又叫做 Client 编译器,面向的是对启动性能有要求的客户端程序,采用的优化手段相对简单,因此编译时间较短。

C2 又叫做 Server 编译器,面向的是对峰值性能有要求的服务器端程序,采用的优化手段相对复杂,因此编译时间较长,但同时生成代码的执行效率较高。

在 Java 7 以前,我们需要根据程序的特性选择对应的即时编译器。启动性能有要求的程序,我们采用编译效率较快的 C1。对于执行时间较长的,或者对峰值性能有要求的程序,我们采用生成代码执行效率较快的 C2。

Java 8 默认使用分层编译,可以动态的选择使用C1和C2编译器。方法代码会先被解释器解释执行,然后热点方法首先会被 C1 编译,而后热点方法中的热点会进一步被 C2 编译。

分层编译的引入在于让即时编译更具备灵性,针对不同代码的实际情况选取最佳的编译路径,也是在程序启动速度、编译时间与运行效率之间达到最佳平衡。

那么具体分层编译的运行机制是什么呢?(http://cr.openjdk.java.net/~iveresov/tiered/Tiered.pdf)

  1. 解释执行;(带 profiling , profiling 是指在程序执行过程中,收集能够反映程序执行状态的数据)
  2. 执行不带 profiling 的 C1 代码;
  3. 执行仅带方法调用次数以及循环回边执行次数 profiling 的 C1 代码;
  4. 执行带所有 profiling 的 C1 代码;
  5. 执行 C2 代码。

通常情况下,C2 代码的执行效率要比 C1 代码的高出 30% 以上。

对于 C1 代码的三种状态,按执行效率从高至低则是 1 层 > 2 层 > 3 层

即时编译的触发

Java 虚拟机是根据方法的调用次数以及循环回边的执行次数来触发即时编译的。上边提到,Java 虚拟机在分层编译 0 层、2 层和 3 层执行状态时进行 profiling,其中就包含方法的调用次数和循环回边的执行次数。

循环回边:字节码中可以简单理解为往回跳转的指令;

具体来说,在不启用分层编译的情况下,当方法的调用次数和循环回边的次数的和,超过由参数 -XX:CompileThreshold 指定的阈值时(使用 C1 时,该值为 1500;使用 C2 时,该值为 10000),便会触发即时编译。当启用分层编译时,Java 虚拟机将不再采用由参数 -XX:CompileThreshold 指定的阈值(该参数失效),而是使用另一套阈值系统。在这套系统中,阈值的大小是动态调整的。所谓的动态调整其实并不复杂:在比较阈值时,Java 虚拟机会将阈值与某个系数 s 相乘。该系数与当前待编译的方法数目成正相关,与编译线程的数目成负相关。

系数的计算方法为:

s = queue_size_X / (TierXLoadFeedback * compiler_count_X) + 1

其中X是执行层次,可取3或者4

queue_size_X是执行层次为X的待编译方法的数目;

TierXLoadFeedback是预设好的参数,控制34层,其中Tier3LoadFeedback为5,Tier4LoadFeedback为3

compiler_count_X是层次X的编译线程数目。

通常情况下,方法会首先被解释执行,然后被 3 层的 C1 编译,最后被 4 层的 C2 编译。

http://cr.openjdk.java.net/~iveresov/tiered/Tiered.pdf

即时编译的优化

基于分支的优化

假设应用程序调用该方法时,所传入的 boolean 值皆为 true。那么针对两次判断,false跳转的次数都为 0。C2 可以根据这两个分支 profile 作出假设,在接下来的执行过程中,这两个条件跳转指令仍旧不会发生跳转。基于这个假设,C2 便不再编译这两个条件跳转语句所对应的 false 分支了。

那么优化后的C代码将直接返回0

;

根据条件跳转指令的分支 profile,即时编译器可以将从未执行过的分支剪掉,以避免编译这些很有可能不会用到的代码,从而节省编译时间以及部署代码所要消耗的内存空间。分支 profile 出现仅跳转或者仅不跳转的情况并不多见。即时编译器对分支 profile 的利用也不仅限于“剪枝”。它还会根据分支 profile,计算每一条程序执行路径的概率,以便某些编译器优化优先处理概率较高的路径。当假设失败的情况下,Java 虚拟机给出的解决方案便是去优化,即从执行即时编译生成的机器码切换回解释执行

基于类型的优化

方法内联

公共子表达式消除

数组边界检查消除

逃逸分析

总结:

1.即时编译-将Java字节码编译成可优化可复用的机器码,运行在底层硬件之上,这么做是为了提高代码的执行效率,提高性能峰值,其触发点是热点代码,热点代码是通过方法的调用次数或者回边循环的次数来筛选的

2.分层编译的引入是为了让即时编译更具备灵性,使得虚拟机可以根据实际运行情况以及相应的算法动态选择执行代码的编译路径,通常情况下,热点方法会先被解释执行,然后被C1编译,再被C2编译

   分层编译是一种折衷的方式,既能够满足部分不热的代码能够在短时间内执行完成,也能满足很热的代码能够拥有最好的优化、执行效率.

资料来源:

1.《深入拆解虚拟机》 郑雨迪

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/75054.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

刚体碰撞检测与响应(C++实现)

本文实现一个经典的物理算法:刚体碰撞检测与响应。这个算法用于检测两个刚体(如矩形或圆形)是否发生碰撞,并在碰撞时更新它们的速度和位置。我们将使用C来实现这个算法,并结合**边界框(Bounding Box&#x…

常用的国内镜像源

常见的 pip 镜像源 阿里云镜像:https://mirrors.aliyun.com/pypi/simple/ 清华大学镜像:https://pypi.tuna.tsinghua.edu.cn/simple 中国科学技术大学镜像:https://pypi.mirrors.ustc.edu.cn/simple/ 豆瓣镜像:https://pypi.doub…

鸿蒙小案例-京东登录

效果 代码实现 Entry Component struct Index {build() {Column() {Row() {Image($r(app.media.jd_cancel)).width(20)Text(帮助).fontSize(16).fontColor(#666)}.width(100%).justifyContent(FlexAlign.SpaceBetween)Image($r(app.media.jd_logo)).height(250).width(250)// …

《 Scikit-learn与MySQL的深度协同:构建智能数据生态系统的架构哲学》

在机器学习工程实践中,数据存储与模型训练的割裂始终是制约算法效能的关键瓶颈。Scikit-learn作为经典机器学习库,其与MySQL的深度协同并非简单的数据管道连接,而是构建了一个具备自组织能力的智能数据生态系统。这种集成突破了传统ETL流程的…

华为AI-agent新作:使用自然语言生成工作流

论文标题 WorkTeam: Constructing Workflows from Natural Language with Multi-Agents 论文地址 https://arxiv.org/pdf/2503.22473 作者背景 华为,北京大学 动机 当下AI-agent产品百花齐放,尽管有ReAct、MCP等框架帮助大模型调用工具&#xff0…

关于软件bug描述

软件缺陷(Defect),常常又被叫做Bug。 所谓软件缺陷,即为计算机软件或程序中存在的某种破坏正常运行能力的问题、错误,或者隐藏的功能缺陷。缺陷的存在会导致软件产品在某种程度上不能满足用户的需要。IEEE729-1983对缺…

【元表 vs 元方法】

元表 vs 元方法 —— 就像“魔法书”和“咒语”的关系 1. 元表(Metatable):魔法书 是什么? 元表是一本**“规则说明书”**,它本身是一个普通的 Lua 表,但可以绑定到其他表上,用来定义这个表应该…

Spring Boot 通过全局配置去除字符串类型参数的前后空格

1、问题 避免前端输入的字符串参数两端包含空格,通过统一处理的方式,trim掉空格 2、实现方式 /*** 去除字符串类型参数的前后空格* author yanlei* since 2022-06-14*/ Configuration AutoConfigureAfter(WebMvcAutoConfiguration.class) public clas…

C语言核心知识点整理:结构体对齐、预处理、文件操作与Makefile

目录 结构体的字节对齐预处理指令详解文件操作基础Makefile自动化构建总结 1. 结构体的字节对齐 字节对齐原理 内存对齐:CPU访问内存时,对齐的地址能提高效率。操作系统要求变量按类型大小对齐。对齐规则: 每个成员的起始地址必须是min(成…

VBA+BOS单据+插件,解决计划任务跟踪的问题之二:导入ERP

第二步,就是要将拆分好的任务导入ERP了 1、将建一个BOS单据叫“任务池”,大概是这样的 然后在拆分工具中进行导数据,点击“数据导出准备”,跳转到“导入ERP”界面,然后点“获取数据”,将拆分好的数据转过来…

使用uglifyjs对静态引入的js文件进行压缩

前言 因为有时候js文件没有npm包,或者需要修改,只能引入静态的js,那么这个时候就可以对js进行压缩了。我其实想通过vite、webpack等插件进行压缩的,可是他都不能定位到public目录下面的文件,所以我只能自己压缩了。编…

蓝桥杯 web 水果拼盘 (css3)

做题步骤: 看结构:html 、css 、f12 分析: f12 查看元素,你会发现水果的高度刚好和拼盘的高度一样,每一种水果的盘子刚好把页面填满了,所以咱们就只要让元素竖着排列,加上是竖着,排不下的换行…

差分音频转单端音频单电源方案

TI LMV321介绍 TI的LMV321是单通道的低压轨到轨输出运算放大器,适用于需要低工作压、节省空间和低成本的应用。 其中,芯片设计中的轨到轨输出(Rail-to-Rail Output) 是指通过特定的电路设计,使芯片(如运算…

Pandas 库

Pandas 是一个开源的数据分析和数据处理库,它是基于 Python 编程语言的。 Pandas 提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据 Pandas 是数据科学和分析领域中常用的工具之一,它使得用户能够…

Vue 3 的<Teleport>功能与用法

Vue 3 的 <Teleport> 功能与用法 1. 基本用法 <Teleport> 是 Vue 3 的一个内置组件&#xff0c;允许将组件的内容渲染到 DOM 中的任意位置&#xff0c;而不改变其逻辑结构。以下是基本用法&#xff1a; 定义目标 DOM 元素&#xff1a;<div id"teleport-…

MySQL随机获取记录之方法(The Method of Randomly Obtaining Records in MySQL)

MySQL中如何随机获取一条记录 随机获取一条记录是在数据库查询中常见的需求&#xff0c;特别在需要展示随机内容或者随机推荐的场景下。在 MySQL 中&#xff0c;有多种方法可以实现随机获取一条记录&#xff0c;每种方法都有其适用的情况和性能特点。在本文中&#xff0c;我们将…

synchronized锁升级详解

synchronized锁升级详解 synchronized是Java中实现线程同步的关键字&#xff0c;它在JVM内部实现了锁的升级机制&#xff0c;从偏向锁到轻量级锁再到重量级锁&#xff0c;这种优化是为了减少锁操作带来的性能开销。 1. 锁的四种状态 Java对象头中的Mark Word会记录锁的状态&…

C++函数如何返回多个参数

在编程中&#xff0c;我们经常会遇到需要函数返回多个值的场景。虽然 C 函数不能直接返回多个参数&#xff0c;但通过一些间接的方法&#xff0c;我们可以轻松实现这一需求。本文将详细介绍几种常见的实现方式&#xff0c;并分析它们的优缺点和适用场景。 1. 引言 在 C 中&…

最新版PhpStorm超详细图文安装教程,带补丁包(2025最新版保姆级教程)

目录 前言 一、PhpStorm最新版下载 二、PhpStorm安装 三、PhpStorm补丁 四、运行PhpStorm 前言 PhpStorm 是 JetBrains 公司推出的 专业 PHP 集成开发环境&#xff08;IDE&#xff09;&#xff0c;专为提升 PHP 开发效率设计。其核心功能包括智能代码补全、实时语法错误检…

【杂谈】Godot4.4导出到Android平台(正式导出)

学博而后可约&#xff0c;事历而后知要。 目录 一、准备二、Gradle构建三、配置Java SDK四、配置Android SDK五、配置密钥 一、准备 本文在前文【杂谈】Godot4.4导出到安卓平台&#xff08;调试导出&#xff09;的基础上&#xff0c;进行正式导出。调试导出并不是真正的编译导…