聊聊JIT是如何影响JVM性能的!

news2024/9/29 12:47:43

文章内容收录到个人网站,方便阅读:http://hardyfish.top/

文章内容收录到个人网站,方便阅读:http://hardyfish.top/

文章内容收录到个人网站,方便阅读:http://hardyfish.top/

在这里插入图片描述

我们知道Java虚拟机栈是线程私有的,每个线程对应一个栈,每个线程在执行一个方法时会创建一个对应的栈帧,栈帧负责存储局部变量变量表、操作数栈、动态链接和方法返回地址等信息,每个方法的调用过程,相当于栈帧在Java栈的入栈和出栈过程

图片

但是栈帧的创建是需要耗费资源的,尤其是对于 Java 中常见的 getter、setter 方法来说,这些代码通常只有一行,每次都创建栈帧的话就太浪费了。

另外,Java 虚拟机栈对代码的执行,采用的是字节码解释执行的方式,考虑到下面这段代码,变量 a 声明之后,就再也不被使用,要是按照字节码指令解释执行的话,就要做很多无用功。

public class A{
    int attr = 0;
    public void test(){
        int a = attr;
        System.out.println("月伴飞鱼");
    }
}

执行如下命令:

javap -v A

可以看到这段代码的字节码指令

图片

我们能够看到 aload_0,getfield ,istore_1 这三个无用的字节码指令操作。

aload_0 从局部变量0中装载引用类型值,getfield 从对象中获取字段,istore_1 将int类型值存入局部变量1

另外,我们知道垃圾回收器回收的目标区域主要是堆,堆上创建的对象越多,GC 的压力就越大。要是能把一些变量,直接在栈上分配,那 GC 的压力就会小一些。

其实,我们说的这几个优化的可能性,JVM 已经通过JIT 编译器(Just In Time Compiler)去做了,JIT 最主要的目标是把解释执行变成编译执行。

为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,这就是 JIT 编译器的功能。

图片

如上图,JVM 会将调用次数很高,或者在 for 循环里频繁被使用的代码,编译成机器码,然后缓存起来,下次调用相同方法的时候,就可以直接使用。

那 JIT 编译都有哪些手段呢?接下来我们详细介绍。

方法内联

方法内联它会把一些短小的方法体,直接纳入目标方法的作用范围之内,就像是直接在代码块中追加代码。这样,就少了一次方法调用,执行速度就能够得到提升,这就是方法内联的概念。

可以使用 -XX:-Inline 参数来禁用方法内联,如果想要更细粒度的控制,可以使用 CompileCommand 参数,例如:

-XX:CompileCommand=exclude,java/lang/String.indexOf

在 JDK 的源码里,也有很多被 @ForceInline注解的方法,这些方法,会在执行的时候被强制进行内联;而被@DontInline注解的方法,则始终不会被内联。

JIT 编译之后的二进制代码,是放在 Code Cache 区域里的。这个区域的大小是固定的,而且一旦启动无法扩容。如果 Code Cache 满了,JVM 并不会报错,但会停止编译。所以编译执行就会退化为解释执行,性能就会降低。不仅如此,JIT 编译器会一直尝试去优化你的代码,造成 CPU 占用上升。

通过参数 -XX:ReservedCodeCacheSize 可以指定 Code Cache 区域的大小,如果你通过监控发现空间达到了上限,就要适当的增加它的大小。

分层编译

HotSpot 虚拟机包含多个即时编译器,有 C1,C2 和 Graal,JDK8 以后采用的是分层编译的模式。

JMV使用额外线程进行即时编译,可以不用阻塞解释执行的逻辑。JIT 通常会在触发之后就在后台运行,编译完成之后就将相应的字节码替换为编译后的代码。

「JIT 编译方式有两种:一种是编译方法,另一种是编译循环。」

具体介绍下几个编译器

「C1 编译器」

C1 编译器是一个简单快速的编译器,主要的关注点在于局部性的优化,适用于执行时间较短或对启动性能有要求的程序,也称为Client Compiler,例如,GUI 应用对界面启动速度就有一定要求。

「C2 编译器」

C2 编译器是为长期运行的服务器端应用程序做性能调优的编译器,适用于执行时间较长或对峰值性能有要求的程序,也称为Server Compiler,例如,服务器上长期运行的 Java 应用对稳定运行就有一定的要求。

在 Java7 之前,需要根据程序的特性来选择对应的 JIT,虚拟机默认采用解释器和其中一个编译器配合工作。

「分层编译」

Java7 引入了分层编译,这种方式综合了 C1 的启动性能优势和 C2 的峰值性能优势,我们也可以通过参数 -client或者-server 强制指定虚拟机的即时编译模式。

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

注意:在 Java8 中,默认开启分层编译,-client 和 -server 的设置已经是无效的了。

如果只想开启 C2,可以关闭分层编译(-XX:-TieredCompilation),如果只想用 C1,可以在打开分层编译的同时,使用参数:-XX:TieredStopAtLevel=1

我们可以通过 java -version命令行可以直接查看到当前系统使用的编译模式:

C:\Users\Administrator>java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

mixed mode代表是默认的混合编译模式,除了这种模式外,我们还可以使用-Xint参数强制虚拟机运行于只有解释器的编译模式下,这时 JIT 完全不介入工作;也可以使用参数-Xcomp强制虚拟机运行于只有 JIT 的编译模式下

逃逸分析

下面着重讲解一下逃逸分析,这个知识点在面试的时候经常会被问到。

有这样一个问题:我们常说的对象,除了基本数据类型,一定是在堆上分配的吗?

答案是否定的,通过逃逸分析,JVM 能够分析出一个新的对象的使用范围,从而决定是否要将这个对象分配到堆上。逃逸分析现在是 JVM 的默认行为,可以通过参数-XX:-DoEscapeAnalysis 关掉它。

那什么样的对象算是逃逸的呢?可以看一下下面的两种典型情况。

如代码所示,对象被赋值给成员变量或者静态变量,可能被外部使用,变量就发生了逃逸。

public class EscapeAttr {
    Object attr;
    public void test() {
        attr = new Object();
    }
}

再看下面这段代码,对象通过 return 语句返回。由于程序并不能确定这个对象后续会不会被使用,外部的线程能够访问到这个结果,对象也发生了逃逸。

public class EscapeReturn {
    Object attr;
    public Object test() {
        Object obj = new Object();
        return obj;
    }
}

那逃逸分析有什么好处呢?

「1. 栈上分配」

如果一个对象在子程序中被分配,指向该对象的指针永远不会逃逸,对象有可能会被优化为栈分配。栈分配可以快速地在栈帧上创建和销毁对象,不用再分配到堆空间,可以有效地减少 GC 的压力。

「2. 分离对象或标量替换」

但对象结构通常都比较复杂,如何将对象保存在栈上呢?

JIT 可以将对象打散,全部替换为一个个小的局部变量,这个打散的过程,就叫作标量替换(标量就是不能被进一步分割的变量,比如 int、long 等基本类型)。也就是说,标量替换后的对象,全部变成了局部变量,可以方便地进行栈上分配,而无须改动其他的代码。

从上面的描述我们可以看到,并不是所有的对象或者数组,都会在堆上分配。由于JIT的存在,如果发现某些对象没有逃逸出方法,那么就有可能被优化成栈分配。

「3.同步消除」

如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步。

注意这是针对 synchronized 来说的,JUC 中的 Lock 并不能被消除。

要开启同步消除,需要加上 -XX:+EliminateLocks 参数。由于这个参数依赖逃逸分析,所以同时要打开 -XX:+DoEscapeAnalysis 选项。

比如下面这段代码,JIT 判断对象锁只能被一个线程访问,就可以去掉这个同步的影响。

public class SyncEliminate {
    public void test() {
        synchronized (new Object()) {
        }
    }
}

小结

文章内容收录到个人网站,方便阅读:http://hardyfish.top/

JIT 是现代 JVM 主要的优化点,能够显著地提升程序的执行效率。从解释执行到最高层次的 C2,一个数量级的性能提升也是有可能的。

注意:JIT 优化并不见得每次都有用,比如代码中如果发生死循环。但如果你在启动的时候,加上-Djava.compiler=NONE 参数,禁用 JIT,它就能够执行下去。

这篇文章中我们主要看了方法内联、逃逸分析等概念,了解到一些方法在被优化后,对象并不一定是在堆上分配的,它可能在被标量替换后,直接在栈上分配。这几个知识点也是在面试中经常被问到的。

JIT 的这些优化一般都是在后台进程默默地去做了,我们不需要关注太多。同时Code Cache 的容量达到上限,会影响程序执行的效率,但除非你有特别多的代码,默认的 240M 一般来说,足够用了。

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

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

相关文章

pwn练习(1)

[BJDCTF 2020]babystack2.0 p.sendline(-1): 通过之前建立的连接,向服务器发送字符串"-1"和一个换行符。这可能是为了触发某个特定的行为或条件。 from pwn import* premote(node4.anna.nssctf.cn,28575) p.sendline(-1) payloadbA*(0X108)p64(0x40072A) …

基于SSM的“实习支教中小学学校信息管理系统”的设计与实现(源码+数据库+文档)

基于SSM的“实习支教中小学学校信息管理系统”的设计与实现(源码数据库文档) 开发语言:Java 数据库:MySQL 技术:SSM 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 主页 注册页面 师资力量界面 个…

十个最好看的桌面屏保 最好用的桌面屏保软件推荐

屏保是指在计算机长时间空闲时自动启动的一种程序,屏保作用可以保护你的屏幕隐私,屏保还可以起到美化作用。今天小编给大家带来最酷最好看的十个桌面电脑屏保:芝麻时钟(下载地址:https://clock.zhimasoft.cn/?bili &a…

汽车总线之---- LIN总线

Introduction LIN总线的简介,对于传统的这种点对点的连接方式,我们可以看到ECU相关的传感器和执行器是直接连接到ECU的,当传感器和执行器的数量较少时,这样的连接方式是能满足要求的,但是随着汽车电控功能数量的不断增…

linux 内核代码学习(十)--Linux内核启动和文件系统

前面第九章介绍了linux内核文件系统从软盘启动的几种方式:1、从软盘直接启动的linux,软盘上包括内核及简单文件系统;2、从软盘直接启动的linux,将内核与文件系统分别放置在一张软盘上;3、Grub做为引导程序,…

【软件类】OPPO 2024届校招正式批笔试题-研发通用(C卷)

昨天做了一场OPPO的,BC两题都速切了,其中B为语法题,C为思维题,想明白mid的范围即可,但A题真给我搞汗流浃背了,倒不是A题难,而是数据卡的很死。从下午一直调到了晚上还是TLE了,最后出…

测试矩阵:快速完成测试用例设计的高效模板

一般来说,测试矩阵用于整理测试思路,便于其他人进行测试审核,后续测试用例基本基于测试矩阵内容进行,测试矩阵主要元素为测试模块、测试场景和测试点,其他内容可在设计测试用例时再进行完善,以下模板包含了…

上海我店:创新模式引领本地生活新风尚

近年来,一个名为“上海我店”的新兴平台在网络空间中迅速崛起,其公布的业绩令人瞩目——在短短三年内,交易流水已跨越百亿大关,并在最近一个月内迎来了近百万的新增注册用户。这一强劲的增长势头,无疑吸引了众多商家和…

服务器数据恢复—raid磁盘故障导致数据库文件损坏的数据恢复案例

服务器存储数据恢复环境&故障: 存储中有一组由3块SAS硬盘组建的raid。上层win server操作系统层面划分了3个分区,数据库存放在D分区,备份存放在E分区。 RAID中一块硬盘的指示灯亮红色,D分区无法识别;E分区可识别&a…

STM32F407HAL库输出互补PWM波以及死区时间计算

互补PWM波配置 STM32F407VET6的高级定时器TIM1、TIM8可以生成互补的PWM波,用HAL库配置非常方便。 我们使用高级定时器TIM1,选择一个通道(我这里选择通道二),然后选择PWM Generation CH2 CH2N。这里N的意思是互补&…

基于趋近律的滑模控制器设计、仿真(S-function)

目录 一、什么是滑模控制?1. 滑模面2. 控制策略3. 抗干扰和鲁棒性4. 滑模控制的应用 二、什么是趋近律?1. 趋近律三大设计目标2. 常见的趋近律形式1. 等速趋近律2. 指数趋近律3. 幂次趋近律 三、滑模控制器设计四、滑模仿真示例1. Simulink仿真框图2. 不同k值下的仿…

JAVA全球美业新风尚国际版同城美容美发到店上门一体化服务系统小程序源码

全球美业新风尚,美丽触手可及!✨ 🌍 开篇:引领国际美业新潮流 在这个追求个性与美丽的时代,美容美发已不再是简单的日常护理,它成为了我们展现自我、追求品质生活的一种方式。而“全球美业新风尚国际版同…

ASP.NET Zero是什么?适合哪些业务场景?

一、ASP.NET Zero是什么? ASP.NET Zero 是一个基于 ASP.NET Boilerplate (ABP) 框架的模板项目,它提供了预建的页面和强大的基础设施架构,以便开发者能够快速开发应用层。它的特点包括但不限于: 多合一解决方案:提供多…

4.数据结构与算法-线性表的顺序表示和实现

2.1 线性表的定义和特点 线性表例子 线性表的逻辑特征 2.2 案例引入 案例2.1 案例2.1:一元多项式的运算 案例2.2:系数多项式的运算 用时间换取空间--线性数组相对链式访问速度快 但这种方法链式更节省空间,所以用时间换取空间 案例2.3&…

2024平价电容笔推荐!精选五大靠谱电容笔测评盘点!

现在电子设备已经成为我们生活、学习和工作中不可或缺的重要工具。而电容笔作为与电子设备紧密配合的配件,其重要性也日益凸显,为我们的数字操作体验带来极大的便利和提升。然而,市场上电容笔的品牌众多,价格、性能和品质参差不齐…

工业制氮机在食品行业的应用优势

作为一种高效、环保的设备,制氮机通过物理方法从空气中分离出高纯度氮气,为食品行业提供了全方位的品质提升和安全保障。本文将详细探讨工业制氮机在食品行业的应用优势。 一、保障食品质量与安全性 工业制氮机在食品行业中最为显著的应用优势之一&#…

Ubuntu-WSL2一键设置代理操作

现状: Window11中拥有自己的代理软件 ,可以科学上网已在WSL2中安装Ubuntu22.04 需求: Ubuntu-WSL2实现科学上网 实现: 参考:为 WSL2 一键设置代理 Linux 子系统中的网关指向的是 Windows,DNS 服务器指…

深入调研400+手游公司,此时正是入行好时机?

自2022年起,手游市场在疫情阴霾消散后遭遇的增长瓶颈,成为了业界持续聚焦的热点议题。转眼间,两年时光匆匆流逝,这一领域的现状与前景究竟几何? 国际知名发行商Sandsoft最新出炉的《发行商洞察报告》中,对…

开源物联网技术--TFT_LCD屏驱动软硬件设计分享

01 一、物联网系统中为什么要使用TFT-LCD屏 在物联网系统中使用TFT-LCD(薄膜晶体管液晶显示器)驱动芯片的原因主要可以归纳为以下几点: 专业性与高效性 专业图形处理:TFT-LCD驱动芯片内置了专业的图形处理引擎,能够…

探索Langchain与国内智谱清言:构建先进的智能对话系统[第二课]

在当今的人工智能领域,构建一个能够流畅对话的智能系统是许多企业和开发者的目标。Langchain和国内智谱清言(BigModel)提供了强大的工具和API,使得这一目标变得更加容易实现。 语言模型的力量 语言模型是智能对话系统的核心&am…