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有着“一次编译,处处运行”的特性,会将编译阶段分成两部分:

  1. 前端编译:由javac编译成字节码,该过程会进行词法分析、语法分析、语义分析。
  2. 后端编译:由解释器字节码解释为机器码来执行。

而后端编译又可以根据执行的方式来分为两种:

  1. 解释执行:一行一行解释成机器码再执行,每次调用时都需要重新逐条解释执行。
  2. 编译执行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有这么几个关键特性:

  1. 由Java编写,对于lambda表达式、stream流的使用要更加友好。
  2. 会做虚函数的内联部分逃逸分析等更深层次的优化。
  3. 对于代码的分支预测和选择优化要更好。

总结就是:
Java执行过程有两步:

  1. 前端编译:由javac编译成字节码。
  2. 后端编译:由解释器字节码解释为机器码来执行。

后端编译有两种执行方式:

  1. 解释执行:一行一行解释成机器码再执行,每次调用时都需要重新逐条解释执行。
  2. 编译执行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即时编译器相关推荐

  1. 关于Java的JIT(即时编译器)知识整理

    文章目录 前言 一.JIT(即时编译器) 1.1 解释执行和编译执行的区别 1.2 Java代码编译过程 1.3 JIT是什么 二.HotSpot是什么 2.1 说JIT比解释快,其实说的是" ...

  2. Java JIT在运行JDK代码时是否作弊?

    本文翻译自:Does Java JIT cheat when running JDK code? I was benchmarking some code, and I could not get i ...

  3. JAVA JIT编译

    JAVA JIT编译 分别使用lambda表达式以及普通for循环做测试 默认情况下启用JIT package com.gao.demo;import java.util.ArrayList; imp ...

  4. jvm执行引擎全解,java解释器即时编译器,全都讲明白

    目录 一.开局一张图 二.执行引擎概述 三.执行引擎工作过程 java代码编译和执行的过程 问题:什么是解释器(Interpreter),什么是JIT编译器? 问题:为什么说java是半编译半解释型语 ...

  5. java jit技术_如何理解JIT编译技术?

    JIT,就是JUST IN TIME的缩写,在计算机技术体系内,JIT指一种动态编译(Dynamic Compilation)技术. 先解释几个概念: 解释(Interpreter):解释就是把源程序 ...

  6. java jit 编译器_浅谈对JIT编译器的理解。

    1. 什么是Just In Time编译器? Hot Spot 编译 当 JVM 执行代码时,它并不立即开始编译代码.这主要有两个原因: 首先,如果这段代码本身在将来只会被执行一次,那么从本质上看,编 ...

  7. java jit 即时编译_JVM即时编译(JIT)

    版权声明:本文为CSDN博主「nogos」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明. 原文链接:https://blog.csdn.net/sunxiang ...

  8. 浅谈Java JIT编译器概念

    文章目录 一.解释器 二.编译器 1.传统编译器 2.GraalVM 三.热点代码 四.编译器优化技术 1.方法内联 2.锁消除 3.标量替换 4.逃逸分析 一.解释器 Java程序在运行的时候,主要 ...

  9. jit java 怎么配置_新的Java JIT编译器Graal简介

    在本教程中,我们将深入研究名为Graal的新Java实时(JIT)编译器. 让我们首先解释JIT编译器的作用. 当我们编译Java程序时(例如,使用  javac命令),我们最终将源代码编译成代码的二 ...

最新文章

  1. CodeForces - 1370E Binary Subsequence Rotation(思维)
  2. myeclipse 8.5最新注册码(过期时间到2016年)
  3. 微软 PowerBI 被评为商业智能领导者-13年的企业产品奋斗史解读
  4. C语言:--位域和内存对齐
  5. python颜色表_数据库表连接的简单解释 | 图文并茂,通俗易懂
  6. Git使用教程之从远程库克隆项目(四)
  7. 汇编语言软件延时1s
  8. hihocoder 1043 完全背包
  9. 【Daily】IE弹窗SQL分割字符串
  10. OpenCV 二值化
  11. 怎么批量删除html里的字段,shp文件怎么删除字段
  12. 人工神经网络算法有哪些,人工神经网络算法优点
  13. apple id邮箱停止服务器,Apple ID被大范围停用,你可以看看这个帖子。
  14. 1650显卡学计算机,1650ti显卡属于什么档次?
  15. 我为什么要立刻放弃React而使用Vue?
  16. 【人工智能】人脸识别系统【实验报告与全部代码】(QDU)
  17. CentOS中使用VeraCrypt:安装及创建整个加密硬盘
  18. 【My Electronic Notes系列——组合逻辑电路】
  19. 《计算机工程与应用》投稿录用经历记录
  20. GPRS GPRS(General Packet Radio Service)是通用分组无线服务技术的简称,它是GSM移动电话用户可用的一种移动数据业务,属于第二代移动通信中的数据传输技术...

热门文章

  1. java万年历的设计总结_java万年历设计报告
  2. Kubernetes1.4新特性前瞻:设置JOB执行计划
  3. Ubuntu20.04之IDEA安装及idea项目运行演示,手把手教学|超级详细,建议收藏
  4. 文献阅读---多年生黑麦草种质中与耐热性相关的生理性状、分子标记和叶绿素分解代谢基因的自然变异
  5. Jquery做的网页版连连看(初稿)
  6. 【二维前缀和】304. 二维区域和检索 - 矩阵不可变
  7. 人大金仓命令行客户端工具KSQL系列2
  8. Bentley 软件公司发起 2021 基础设施数字化光辉大奖赛项目征集活动
  9. 蓝牙系统中的主机与控制器
  10. 免费的PHP在线解密工具源码