网站首页 > java教程 正文
在Java编译原理(javac) 中我们已经讲述了Java编译中的前端编译(javac),今天我们就看一下后端编译。
1. 为什么需要后端编译(JIT)
当我们的字节码文件被虚拟机加载过后,其实就可以解释执行,也就是说即使没有后端编译我们的Java程序也可以运行。之所以需要后端编译是因为解释执行虽然会提高程序的启动速度,但当程序稳定运行以后,运行速度不会再有所改善。计算机的世界与天下武功一样,唯快不破,为了不断提高我们的程序运行速度,我们需要在程序运行过程中对特定代码进行编译,将本地代码编译成机器可以直接识别的机器代码。
2. HotSpot虚拟机的JIT
HotSpot VM中集成了两种编译器,Client Compiler和Server Compiler,它们的作用也不同。Client Compiler注重启动速度和局部的优化,Server Compiler则更加关注全局的优化,性能会更好,但由于会进行更多的全局分析,所以启动速度会变慢。两种编译器有着不同的应用场景,在虚拟机中同时发挥作用。
2.1 Client Compiler
HotSpot VM中带有一个Client Compiler C1编译器,它主要做以下事情:
- 局部简单可靠的优化,比如字节码上进行的一些基础优化,方法内联、常量传播等,放弃许多耗时较长的全局优化。
- 将字节码构造成高级中间表示(High-level Intermediate Representation,以下称为HIR),HIR与平台无关,通常采用图结构,更适合JVM对程序进行优化。
- 最后将HIR转换成低级中间表示(Low-level Intermediate Representation,以下称为LIR),在LIR的基础上会进行寄存器分配、窥孔优化(局部的优化方式,编译器在一个基本块或者多个基本块中,针对已经生成的代码,结合CPU自己指令的特点,通过一些认为可能带来性能提升的转换规则或者通过整体的分析,进行指令转换,来提升代码性能)等操作,最终生成机器码。
2.2 Server Compiler
Server Compiler主要关注一些编译耗时较长的全局优化,甚至会还会根据程序运行的信息进行一些不可靠的激进优化。这种编译器的启动时间长,适用于长时间运行的后台程序,它的性能通常比Client Compiler高30%以上。目前,Hotspot虚拟机中使用的Server Compiler有两种:C2和Graal。
关于Client Compiler和Server Compiler后面我会单独写一下具体的编译过程。
3. 分层编译
即时编译器编译代码需要时间,一般编译出优化程度更高的代码(影响程序启动响应速度,但是会提高运行效率),编译会花费更多的时间。为了在程序启动响应速度和运行效率之间达到平衡,HotSpot虚拟机采用分层编译,分层编译的思想将JVM的执行状态划分为5层:
- 第1层:解释执行
- 第2层:执行不带Profiling(收集反应执行状态的数据)的C1本地代码
- 第3层:执行带方法调用次数和回边调用次数Profiling的C1本地代码
- 第4层:执行所有Profiling的C1本地代码
- 第5层:执行C2本地代码
3.1 编译条件
在程序运行过程中,热点代码会触发编译,热点代码有以下两类:
- 被多次调用的方法
- 被多次执行的循环体
热点代码通过热点探测的方式进行判定,判定的方式大约有两种:
- 基于采样的热点探测:虚拟机周期性检查线程的栈顶,如果某个方法经常出现在栈顶,那么该方法即为热点方法。这种实现方式简单高效,但是精确度不够,一些阻塞的方法会被误判为热点方法。
- 基于计数器的热点探测:对每个方法(甚至方法块)建立计数器,执行次数超过一定的阀值就被判定为热点方法。
Hotspot虚拟机采用的是基于计数器的热点探测,虚拟机为每个方法准备了两类计数器:
- 方法调用计数器
- 回边计数器
在分层编译开启的情况下,触发编译由以下条件来判断:
- 方法调用次数大于由参数-XX:TierXInvocationThreshold指定的阀值乘以系数
- 方法调用次数大于由参数-XX:TierXMINInvocationThreshold指定的阀值乘以系数,并且方法调用次数和循环回边次数之和大于由参数-XX:TierXCompileThreshold指定的阀值乘以系数时
以上两个条件满足其中一个即可触发即时编译,系数会由虚拟机根据当前编译的方法数以及编译线程数动态调整。
公式如下:
// i为方法调用计数器记录的方法调用次数
// b为回边计数器记录的循环回边次数
i > TierXInvocationThreshold * s || (i > TierXMINInvocationThreshold * s && i + b > TierXCompileThreshold * s)
本期的JIT即时编译介绍到这,我是shysh95,我们下期再见!!!
猜你喜欢
- 2024-10-01 Java培训:不同编程语言中的JIT编译
- 2024-10-01 Java 代码编译的3种方式,其中JIT最重要!
- 2024-10-01 java考试题:选择题(1-10)共15题(java选择题100道)
- 2024-10-01 Java中文编译出现错误的问题(java中文编译出现错误的问题怎么办)
- 2024-10-01 程序的编译和解释,你还知道是什么吗?
- 2024-10-01 Java虚拟机编译原理二:Java的类加载过程
- 2024-10-01 Java虚拟机编译《四》(深入浅出:java虚拟机设计与实现)
- 2024-10-01 这次我们来学习深入解析java虚拟机:C2编译器,编译流程吧
- 2024-10-01 Java带包结构命令行编译(java 包结构)
- 2024-10-01 Jenkins+Gitlab+Nginx+SonarQube+Maven编译Java项目自发布与回退
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)