Java - JIT即时编译器
Java - JIT即时编译器
- 前言
- 一. JVM编译器
- 1.1 Client Compiler
- 1.2 Server Compiler
- 1.2.1 C2 Compiler
- 1.2.2 Graal Compiler
- 二. JIT和编译优化
- 2.1 中间表达形式(IR)
- 2.2 方法内联
- 2.3 逃逸分析
- 2.4 Loop Transformations
- 2.5 窥孔优化与寄存器分配
前言
我们知道,Java有着“一次编译,处处运行”的特性,会将编译阶段分成两部分:
- 前端编译:由
javac
编译成字节码,该过程会进行词法分析、语法分析、语义分析。 - 后端编译:由
解释器
将字节码解释为机器码来执行。
而后端编译又可以根据执行的方式来分为两种:
- 解释执行:一行一行解释成机器码再执行,每次调用时都需要重新逐条解释执行。
- 编译执行JIT(Just In Time):将执行的比较多的热点代码编译优化成本地代码,提高执行效率。(好比加了缓存)
热点代码:
当方法或者代码块在一定时间内的调用次数超过JVM规定的阈值,则会被编译,存入codeCache中。
codeCache:
代码缓存区,主要存放JIT所编译的代码,同时还有Java所使用的本地方法代码也会存储在codecache中,例如
Object.wait()
,Object.notify()
等被native
修饰的都是所谓的本地方法。
Java编译的整个过程为:
一. JVM编译器
JVM有两种编译器:
- Client Compiler(C1编译模式):着重于启动速度和局部优化。
- Server Compiler(C2编译模式):着重于全局优化。性能更好,但是启动速度慢。
对于HotSpot而言,一共有三种编译模式:
- 混合模式(Mixed Mode):C1和C2编译模式混合起来使用(默认的模式),若希望单独使用C1编译模式或者C2编译模式,分别使用
-client
,-server
参数来打开。 - 解释模式(Interpreted Mode):
- 编译模式(Compiled Mode):
输入命令java -vsersion
可以查看当前的编译模式:
1.1 Client Compiler
HotSpot VM中的Client Compiler为C1编译器,启动速度快,主要做三件事情:
- 局部优化,例如字节码上的基础优化、方法内联、常量传播。
- 将字节码构造成高级中间表示(HIR)。
- 将HIR转换成低级中间表示(LIR),在LIR基础上进行局部优化,生成机器码。
1.2 Server Compiler
主要关注一些编译比较耗时的全局优化,适用于长时间运行的后台程序,其性能一般比Client Compiler要高30%以上,Server Compiler有两种。
1.2.1 C2 Compiler
C2是Hotspot的默认Server编译器,C2使用一种控制流和数据流相结合的图数据结构(Ideal Graph,后面简称IG),其表示当前程序的数据流向和指令间的依赖关系。而C2则通过这种图结构来优化步骤。
1.2.2 Graal Compiler
启用方式:
-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler
与C2编译器相比而言,Graal有这么几个关键特性:
- 由Java编写,对于
lambda
表达式、stream
流的使用要更加友好。 - 会做虚函数的内联、部分逃逸分析等更深层次的优化。
- 对于代码的分支预测和选择优化要更好。
总结就是:
Java执行过程有两步:
- 前端编译:由
javac
编译成字节码。 - 后端编译:由
解释器
将字节码解释为机器码来执行。
后端编译有两种执行方式:
- 解释执行:一行一行解释成机器码再执行,每次调用时都需要重新逐条解释执行。
- 编译执行JIT(Just In Time):将热点代码编译优化成
codeCache
。
JVM虚拟机有两种编译器:Client / Server Compiler
比较项 | Client Compiler | Server Compiler |
---|---|---|
启动速度 | 快 | 慢 |
包含的编译器 | C1 | C2,Graal |
性能 | 一般 | 高30% |
主要的工作 | 字节码优化、方法内联。将字节码转HIR,再转LIR | 主要关注一些编译耗时较长的全局优化,甚至会还会根据程序运行的信息进行一些不可靠的激进优化 |
优化范围 | 局部优化 | 全局优化 |
二. JIT和编译优化
JIT的触发时机:JVM根据某个方法的调用次数和循环回边的执行次数来触发。当两者的次数和超过-XX:CompileThreshold
指定的阈值,则触发JIT编译。
C1的默认阈值为1500.
C2的默认阈值为10000.
JIT在进行编译的时候,会做一些优化操作。
2.1 中间表达形式(IR)
首先,编译的阶段由上文我们知道分为了:
- 前端:通过词法分析、语法分析、语义分析生成中间表达形式(IR),例如字节码。
- 后端:对IR进行优化,生成目标代码。
那么这些IR优化一般有哪些内容呢?
- 识别冗余赋值。
- 删除无用代码。
2.2 方法内联
方法内联的含义:在编译过程中遇到方法调用时,将目标方法的方法体纳入编译范围之中,并取代原方法调用的优化手段。 并且JIT大部分的优化都是在内联的基础上进行的。
以get/set
为例,区别如下:
- 无方法内联:调用时,程序执行时需要保存当前方法的执行位置,创建并压入用于getter/setter的栈帧、访问字段、弹出栈帧,最后再恢复当前方法的执行。
- 有方法内联:程序执行到对应的位置时,直接进行字段访问即可。
方法内联的优劣势:
- 优势:内联的方法越多,生成代码的执行效率越高。
- 劣势:内联的方法越多,JIT编译时间也就越长
2.3 逃逸分析
逃逸分析可以分析在程序的哪些地方可以访问到指针,JIT会对新建的对象进行逃逸分析,判断对象是否逃逸出线程或者方法。 判断对象是否逃逸的依据有两种:
- 对象是否存入堆中,若存入,则其他线程便能获得这个对象的引用。
- 对象是否被传入未知代码(未被内联的代码)中,此时可认为方法调用的调用者以及参数是逃逸的。
2.4 Loop Transformations
JIT编译器会对循环做一些转换,其中最重要的是循环展开和循环分离。
循环展开:以牺牲程序二进制码大小为代价来优化程序的执行速度,通过减少或消除控制程序循环的指令,来减少计算开销(空间换时间)。
例如:
public void test(){for(int i = 0;i<100;i++){run(i); }
}
经过循环展开后得到:
public void test(){for(int i = 0;i<100;i+=5){run(i); run(i+1); run(i+2); run(i+3); run(i+4); }
}
效果:减少循环次数
循环分离:把循环中一次或多次的特殊迭代分离出来,在循环外执行。
例如:
原本的代码如下:
int a = 10;
for(int i = 0;i<10;i++){b[i] = x[i] + x[a];a = i;
}
经过循环分离后:(将特殊情况第一次a=10
分离了出来)
b[0] = x[0] + 10;
for(int i = 1;i<10;i++){b[i] = x[i] + x[i-1];
}
2.5 窥孔优化与寄存器分配
窥孔优化作为最后一步JIT优化。将编译器所生成的中间代码的某些组合替换为效率更高的指令组。
例如:
y=x*3
变成:(移位的效率更高)
y=(x<<1)+x
寄存器分配(C2):把频繁使用的变量保存在寄存器中,CPU访问寄存器的速度比内存快得多,就可以提升程序的运行速度。
在窥孔优化和寄存器分配结束后,程序就会被转换成机器码保存到codecache中了。
参考:(详细介绍的请看第一篇文章)
- 基本功 | Java即时编译器原理解析及实践
- JVM学习笔记之CodeCache
Java - JIT即时编译器相关推荐
- 关于Java的JIT(即时编译器)知识整理
文章目录 前言 一.JIT(即时编译器) 1.1 解释执行和编译执行的区别 1.2 Java代码编译过程 1.3 JIT是什么 二.HotSpot是什么 2.1 说JIT比解释快,其实说的是" ...
- Java JIT在运行JDK代码时是否作弊?
本文翻译自:Does Java JIT cheat when running JDK code? I was benchmarking some code, and I could not get i ...
- JAVA JIT编译
JAVA JIT编译 分别使用lambda表达式以及普通for循环做测试 默认情况下启用JIT package com.gao.demo;import java.util.ArrayList; imp ...
- jvm执行引擎全解,java解释器即时编译器,全都讲明白
目录 一.开局一张图 二.执行引擎概述 三.执行引擎工作过程 java代码编译和执行的过程 问题:什么是解释器(Interpreter),什么是JIT编译器? 问题:为什么说java是半编译半解释型语 ...
- java jit技术_如何理解JIT编译技术?
JIT,就是JUST IN TIME的缩写,在计算机技术体系内,JIT指一种动态编译(Dynamic Compilation)技术. 先解释几个概念: 解释(Interpreter):解释就是把源程序 ...
- java jit 编译器_浅谈对JIT编译器的理解。
1. 什么是Just In Time编译器? Hot Spot 编译 当 JVM 执行代码时,它并不立即开始编译代码.这主要有两个原因: 首先,如果这段代码本身在将来只会被执行一次,那么从本质上看,编 ...
- java jit 即时编译_JVM即时编译(JIT)
版权声明:本文为CSDN博主「nogos」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明. 原文链接:https://blog.csdn.net/sunxiang ...
- 浅谈Java JIT编译器概念
文章目录 一.解释器 二.编译器 1.传统编译器 2.GraalVM 三.热点代码 四.编译器优化技术 1.方法内联 2.锁消除 3.标量替换 4.逃逸分析 一.解释器 Java程序在运行的时候,主要 ...
- jit java 怎么配置_新的Java JIT编译器Graal简介
在本教程中,我们将深入研究名为Graal的新Java实时(JIT)编译器. 让我们首先解释JIT编译器的作用. 当我们编译Java程序时(例如,使用 javac命令),我们最终将源代码编译成代码的二 ...
最新文章
- CodeForces - 1370E Binary Subsequence Rotation(思维)
- myeclipse 8.5最新注册码(过期时间到2016年)
- 微软 PowerBI 被评为商业智能领导者-13年的企业产品奋斗史解读
- C语言:--位域和内存对齐
- python颜色表_数据库表连接的简单解释 | 图文并茂,通俗易懂
- Git使用教程之从远程库克隆项目(四)
- 汇编语言软件延时1s
- hihocoder 1043 完全背包
- 【Daily】IE弹窗SQL分割字符串
- OpenCV 二值化
- 怎么批量删除html里的字段,shp文件怎么删除字段
- 人工神经网络算法有哪些,人工神经网络算法优点
- apple id邮箱停止服务器,Apple ID被大范围停用,你可以看看这个帖子。
- 1650显卡学计算机,1650ti显卡属于什么档次?
- 我为什么要立刻放弃React而使用Vue?
- 【人工智能】人脸识别系统【实验报告与全部代码】(QDU)
- CentOS中使用VeraCrypt:安装及创建整个加密硬盘
- 【My Electronic Notes系列——组合逻辑电路】
- 《计算机工程与应用》投稿录用经历记录
- GPRS GPRS(General Packet Radio Service)是通用分组无线服务技术的简称,它是GSM移动电话用户可用的一种移动数据业务,属于第二代移动通信中的数据传输技术...
热门文章
- java万年历的设计总结_java万年历设计报告
- Kubernetes1.4新特性前瞻:设置JOB执行计划
- Ubuntu20.04之IDEA安装及idea项目运行演示,手把手教学|超级详细,建议收藏
- 文献阅读---多年生黑麦草种质中与耐热性相关的生理性状、分子标记和叶绿素分解代谢基因的自然变异
- Jquery做的网页版连连看(初稿)
- 【二维前缀和】304. 二维区域和检索 - 矩阵不可变
- 人大金仓命令行客户端工具KSQL系列2
- Bentley 软件公司发起 2021 基础设施数字化光辉大奖赛项目征集活动
- 蓝牙系统中的主机与控制器
- 免费的PHP在线解密工具源码