Java后端编译与优化

news2024/11/18 4:22:24

 如果我们将字节码看作是程序语言的一种中间表示形式,那编译器无论在何时、在何种状态下把Class文件转换成与本地基础设施相关的二进制机器码,它都可以视为整个编译过程的后端。

1 即时编译器

即时编译器是指运行时将热点代码编译成本地机器码,并以各种手段尽可能地进行代码优化的后端编译器。

1.1 解释器与编译器

1.1.1 解释器

将字节码解释成具体平台的机器码。

其主要作用是:

1)当程序需要迅速启动或执行时,解释器可以首先发挥作用,省去编译的时间。

2)节约内存。

3)作为编译器激进优化时后备的逃生门。

1.1.2 编译器

程序启动后,随着时间推移,编译器逐渐发挥作用,把越来越多的代码编译成本地代码,减少解释器的中间损耗,获得更高的执行效率。

HotSpot虚拟机中内置两个(或三个)即时编译器,其中两个分别为“客户端编译器”(Client Compiler)简称为C1编译器和“服务端编译器”(Server Compiler)简称为C2编译器,第三个是JDK10才出现的,长期目标是代替C2点Graal编译器。

1.1.3 分层编译

为了在程序启动响应速度和运行效率之间达到最佳平衡,HotSpot虚拟机在编译子系统中加入了分层编译的功能。在JDK 7 服务端模式虚拟机中作为默认编译策略被开启。

第0层。程序纯解释执行,并且解释器不开启性能监控功能。

第1层。使用客户端编译器将字节码编译为本地代码来运行,进行简单可靠的稳定优化,不开启性能监控功能。

第2层。仍使用客户端编译器执行,仅开启方法及回边次数统计等有限的性能监控功能。

第3层。仍使用客户端编译器执行,开启全部性能监控,除了第2层的统计信息外,还会收集如分支跳转、虚方法调用版本等全部等统计信息。

第4层。使用服务端编译器将字节码编译为本地代码,启用更多耗时更长的优化,还会根据性能监控信息进行一些不可靠的激进优化。

1.2 编译对象与触发条件

1.2.1 编译对象

会被即时编译器编译的目标是“热点代码”,主要由两类:1)被多次调用的方法。2)被多次执行的循环体。

1.2.2 触发条件

判断某段代码是不是热点代码,是否触发即时编译的这种行为称为“热点探测”。进行热点探测并不一定要知道方法具体被调用了多少次,目前主流的热点探测判定方式有两种:

1)基于采样的热点探测。虚拟机会周期性地检查各个线程的调用栈顶,如果发现某些方法经常出现在栈顶,那这个方法就是“热点方法”。

该方法实现简单高效,还可以很容易地获取方法调用关系,缺点是很难精确地确认一个方法的热度,容易受到线程阻塞的影响。

2)基于计数器的热点探测。为每个方法(甚至是代码块)建立计数器,统计方法的执行次数。

该方法实现起来要麻烦些,但是统计结果相对来说更加精确严谨。

       方法调用计数器并不是方法被调用的绝对数,而是一个相对的执行频率。当超过一定时间限度,如果次数仍不足,那该方法的调用计数器就会被减少一半。这个过程被称为计数器热度的衰减,而这段时间被称为半衰周期。

1.3 编译过程

在默认条件下,虚拟机在编译器还未完成编译之前,都仍然将按照解释器方式继续执行代码,而编译动作则在后台的编译线程中进行。

服务端编译器和客户端编译器的编译过程是有所差别的。

1.3.1 客户端编译器

是一个相对简单快速的三段式编译器,主要的关注点在于局部性的优化,而放弃了许多耗时较长的全局优化手段。

图 客户端编译器大致的执行过程

第一阶段:将字节码完成一部分基础优化,如方法内联、常量传播等。然后构造成一种高级中间代码表示(HIR,即与目标机器指令集无关的中间表示)。HIR使用静态单分配(SSA)的形式来代表代码值。

第二阶段:在HIR上完成另一些优化,如空值检查消除、范围检查消除等。然后产生低级中间代码表示(LIR,即与目标机器指令集相关的中间表示)。

最后阶段:使用线性扫描算法在LIR上分配寄存器,并在LIR上做窥孔优化,然后产生机器代码。

1.3.2 服务端编译器

是专门面向服务端的典型应用场景,并为服务器性能配置针对性调整过的编译器,也是一个能容忍很高优化复杂度的高级编译器。

会执行大部份经典优化动作,还可能根据解释器或客户端编译器提供的性能监控信息,进行一些不稳定的预测性激进优化。

2 编译器优化技术

编译器的工作,难道不在于能否成功翻译出机器码,而在于输出代码优化质量的高低。

2.1 方法内联

最重要的优化技术之一。被称为优化之母,除了消除方法调用的成本之外,它更重要的意义是为其他优化手段建立良好的基础。

方法内联是把目标方法的代码原封不动地“复制”到发起调用到方法中。

public class MethodInline {
    static void method1() {
        System.out.println("method1");
    }

    static void method2() {
        System.out.println("method2");
        method1();
    }
}

上面代码经过方法内联后变为:

static void method2() {
    System.out.println("method2");
    System.out.println("method1");
}

在实际的内联过程,因为Java虚方法都必须在运行时进行方法接收者都多态选择,它们都可能存在多于一个版本的方法接收者。

2.1.1 类型继承关系分析(CHA)

为了解决虚方法的内联问题,Java虚拟机首先引入类型继承关系分析技术,范围为整个应用程序。用于确定目前已加载的类中,某个接口是否有多于一种的实现、某个类是否存在子类、某个子类是否覆盖了父类的某个虚方法等信息。

图 Java虚方法内联

2.2 逃逸分析

最前沿的优化技术之一。并不是直接优化代码的手段,而是为其他优化措施提供依据的分析技术。

基本原理:分析对象动态作用域,当一个对象在方法里被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,这种称为方法逃逸;甚至可能被外部线程访问到,称为线程逃逸。

如果证明一个对象不会逃逸到方法或线程之外,则可能为这个对象实例采取不同程度的优化,如:

  1. 栈上分配。如果确定一个对象不会逃逸出线程之外,那可以让这个对象在栈上分配内存(平常在堆中存储对象数据)。对象所占用到内存空间可以随栈帧出栈而销毁。栈上分配支持方法逃逸而不支持线程逃逸。
  2. 标量替换。一个数据已经无法再分解成更小的数据来表示了,称为标量,相反则称为聚合量。如果一个对象不会被方法外部访问,并且这个对象可被拆散,那么程序真正执行的时候将可以不去创建这个对象,而改用直接创建它的若干个被这个方法使用的成员变量来代替。
  3. 同步消除。线程同步本身是一个相对耗时的过程,如果一个变量不会逃逸出线程,那么这个变量的读写肯定就不会有竞争,对这个变量实施的同步措施就可以安全地消除掉。

 2.3 公共子表达式消除

语言无关的经典优化技术之一。含义是:如果一个表达式E之前已经被计算过,并且从先前计算到现在E中所有变量到值都没发生变化,那么E被称为公共子表达式。

int d = (c * b) * 12 + a + b * c。

优化过程为:

c * b 与 b * c是等价的,且这这段过程中,c与b的值没有发生变化。所以c * b 为公共表达式,设c * b = E,则经过优化的代码为:

int = E * 12 + a + E。

2.4 数组边界检查消除

语言相关的经典优化技术之一。Java每次数组元素的读写都带有隐含的条件判断操作(如检查下标是否合法)。

虚拟机会注册一个Segment Fault信号的异常处理器,这样,当下标合法时,对数组的访问不会有任何额外的开销,当不合法时,必须转到异常处理器中恢复中断并抛出NullPointException异常。此时速度远比上面的隐含条件判断操作慢得多。

所以假如下标经常不合法,这样的优化反而会让程序更慢。HotSpot会根据运行期收集到的性能监控信息自动选择合适的方案。

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

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

相关文章

程序员必须掌握哪些算法?——前端开发工程师需要掌握的算法

文章目录 📋前言🎯什么是算法?🎯前端开发工程师需要掌握的算法🧩排序算法(如快速排序、归并排序)🧩搜索算法(如二分搜索)🧩图算法(如广…

【Unity造轮子】2D横版平台跳跃游戏实现多段跳完美手感(含源码)

文章目录 前言先看效果,手感很丝滑原理开始1. 看到检测点的检测范围2. 二段跳实现3. 动画控制器配置 源码扩展完结 前言 随着游戏技术的不断发展,2D横版平台跳跃游戏成为许多玩家的最爱。这类游戏以其简单而有趣的玩法和精致的视觉效果吸引着无数游戏爱…

Kotlin~Decorator装饰器模式

概念 装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。可以运行时动态添加新的功能,而无需改变原来的代码。 特点: 灵活扩展新的功能动态…

接口设计的总结

目录 前言 设计好接口的 36 个锦囊 总结 前言 作为后端开发,不管是什么语言,Java、Go 还是 C,其背后的后端思想都是类似的。我们做后端开发工程师,主要工作就是:如何把一个接口设计好。所以,今天就给大家…

北京大学考研机试题:二叉树

【题目来源】https://www.acwing.com/problem/content/description/3474/【题目描述】 如上图所示,由正整数 1,2,3…… 组成了一颗特殊二叉树。 我们已知这个二叉树的最后一个结点是 n。 现在的问题是,结点 m 所在的子树中一共包括…

MobileNeRF在Windows上的配置

MobileNeRF于2023年提出,源码地址:https://github.com/google-research/jax3d/tree/main/jax3d/projects/mobilenerf ,论文为:《MobileNeRF: Exploiting the Polygon Rasterization Pipeline for Efficient Neural Field Renderin…

QT自定义工具条渐变背景颜色一例

使用样式定义: QWidget* toolbar new QWidget(this);toolbar->setObjectName("main_tool");toolbar->setStyleSheet("#main_tool{background: qlineargradient(x1:0 , y1:0 , x2:1 , y2:0,""stop:0 rgba(0,255,0, 0.2),"&q…

Nuxt3 components公共组件

1.目录结构 效果实现:写一个公共的right组件,在index和about页面同时引用它 2.index页面引入 index页面显示效果 about页面引用及效果

组件的自定义事件

src/components/School.vue <template><div class"school"><h2>学校名称&#xff1a;{{ name}}</h2><h2>学校地址&#xff1a;{{ address }}</h2><button click"sendSchoolName">把学校名给App</button>…

数据集成的强大联盟:Elasticsearch、Kibana、Logstash、MySQL

通常&#xff0c;很多关系数据项目都使用 MySQL。 它对于标准的 CRUD 操作是有益的&#xff0c;但有时我们需要做额外的过程。 当我们搜索某些内容时&#xff0c;我们会消耗资源或合并多个表。 有时&#xff0c;即使不是&#xff0c;可能仍然需要复杂的 SQL 查询。 也许这不是正…

如何查看OpenAI的AccessToken?

如何查看OpenAI的AccessToken&#xff1f; 记录一下如何查看 OpenAI的 AccessToken 文章目录 如何查看OpenAI的AccessToken&#xff1f;前提具体操作总结 前提 &#x1f4a7;首先&#xff0c;在获取AccessToken前&#xff0c;你需要达成 以下两个条件: 拥有一个可用的OpenA…

ARM CORETEX M0简介

ARM CORETEX M0简介 1. M0处理器简单框图 处理器内核&#xff1a;逻辑控制与运算 内部总线系统&#xff1a;单总线将处理器与外部的存储器和外部连接&#xff0c;进行数据交互&#xff08;冯诺依曼架构&#xff0c;数据与指令一起&#xff09; NVIC&#xff1a;嵌套向量中断控…

【Matlab】智能优化算法_亨利气体溶解度优化算法HGSO

【Matlab】智能优化算法_亨利气体溶解度优化算法HGSO 1.背景介绍2.数学模型2.1 亨利定律2.2 HGSO 3.文件结构4.伪代码5.详细代码及注释5.1 Create_Groups.m5.2 Evaluate.m5.3 fun_checkpoisions.m5.4 fun_getDefaultOptions.m5.5 HGSO.m5.6 main.m5.7 sumsqu.m5.8 update_posit…

机器学习总览

机器学习 1.什么是机器学习&#xff1f; 机器学习是使计算机像人类一样学习与行动的科学&#xff0c;并通过观察与现实世界交互的形式向计算机提供数据和信息&#xff0c;从而随着时间的推移以自主的方式改善其学习。 通过经验提高某些任务性能的计算机程序。 人工智能>机器…

FreeRTOS ~(六)信号量 ~ (1/3)信号量解决同步缺陷

前情提要 FreeRTOS ~&#xff08;四&#xff09;同步互斥与通信 ~ &#xff08;1/3&#xff09;同步的缺陷 FreeRTOS ~&#xff08;五&#xff09;队列的常规使用 ~ &#xff08;1/5&#xff09;队列解决同步缺陷 举例子说明&#xff1a;利用信号量解决前述的"同步的缺陷&…

最具价值开源项目收藏--持续更新

轻量级开源笔记应用&#xff08;memos&#xff09; 该项目基于 Go React.js SQLite 技术栈开发&#xff0c;兼具高性能与可定制性&#xff0c;适用于日常生活办公中的各类笔记管理场景。 开源地址&#xff1a;https://github.com/usememos/memos 跨平台无缝传输文件&#…

揭秘python函数:编程艺术的核心力量(3)

文章目录 前言递归lambda表达式lambda 的参数形式无参数位置参数关键字参数缺省参数可变参数1.包裹位置传递2.包裹关键字传递 带判断条件的lambda表达式列表数据按照字典key的值进行排序 高阶函数的使用内置高阶函数1.map()2.reduce()3.filter() 前言 前面我们已经学习了 pyth…

7-测试模型(2个)

目录 1.软件测试V模型 2.软件测试W模型&#xff08;双V模型&#xff09; 1.软件测试V模型 V模型最早是由Paul Rook在2&#xff10;世纪&#xff18;&#xff10;年代后期提出的&#xff0c;目的是改进软件开发的效率和效果。是瀑布模型的变种。 明确地标注了测试过程中存在的…

前端工程打包部署

打包 直接执行第二个脚本build即可 打包后的文件将会放在dist目录下 部署 NGINX&#xff1a;是一款轻量级的Web服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器。其特点是占用内存少&#xff0c;并发能力强&#xff0c;在各大型互联网公司都有非…

R中高效安装包,以ComplexHeatmap包为例

包安装问题解决方案 1. Biocmanager安装 [2. 手动安装]&#xff08;正在更新……&#xff09; 目录 包安装问题解决方案前言1. install.packages()的介绍1.1 install.packages()的工作原理1.2 install.packages()安装失败的原因1.3 解决方案 2. BiocManage安装ComplexHeatmap总…