一 执行引擎
1. 概述
执行引擎时Java虚拟机核心组成部分之一,主要做翻译工作
“虚拟机”是一个相对于“物理机”的概念,两种都具有执行代码的能力
- 区别:
- 物理机执行引擎直接建立在处理器、缓存、指令集和操作系统层面上。
- 虚拟机执行引擎是由软件自行实现的,因此可以不受物理条件制约定定制指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式。
JVM的主要任务是负责装载字节码到其内部,但并不能执行运行在操作系统上。如果要运行java程序,执行引擎的任务就是将字节码指令解释/编译为对应平台的本地机器指令才可以。
2. 工作过程
- 执行引擎在执行过程中,依赖于程序计数器来确定执行什么样的字节码指令
- 通过对象访问定位,访问对象的信息
- 所有的Java虚拟机的执行引擎输入、输出都是一致的:输入的是字节码二进制流,处 理过程是字节码解析执行的等效过程,输出的是执行结果
即时编译器
3. Java代码编译和执行过程
什么是解释器(Interpreter),什么是JIT编译器?
- 解释器(边翻译,边执行)
当Java虚拟机启动时会根据定义的规范对字节码采用逐行解释的方式执行,对每行字节码“翻译”为本地机器指令执行
- JIT(Just In Time Compiler) 编译器(全部翻译,后执行)
就是虚拟机将源代码直接编译成本地机器平台相关的机器语言
为什么说Java时半编译半解释型语言?
在java1.0的时候,java还是解释型语言。后来加入了JIT编译器,二者结合起来执行
4. 为什么解释器与JIT编译器要并存
- 程序启动后,解释器可以马上发挥作用,减少响应时间
- 随着程序运行时间的推移,即时编译器发挥作用,把越来越多的热点代码编译成本地代码,获得更高的执行效率
- 同时,编译器进行激进优化不成立的时候,可以切换为解释器执行
5. 热点代码探测方式
Ⅰ 什么是热点代码?
一个被多次调用的方法,或者循环多次的循环体都可以被称为“热点代码”。因此都可以通过即时编译器编译为本地代码,由于这种编译方式发生在方法执行过程中,被称为栈上替换,或简称OSR(On Stack Replacement)编译
Ⅱ 探测方式
关闭热度衰减
- -XX:CounterHalfLifeTime
设置半衰周期,单位是秒
6. 切换执行方式
- -Xint
解释器模式
- -Xcomp
即使编译器模式
- -Xmixed
混合模式(默认)
7. 编译器分类
HotSpot 中有两个JIT编译器:Client、Server,大多数时候称为:C1编译器、C2编译器
可通过下面两种命令选择,x64下默认使用server
- -client
- -server
C1编译器:对字节码进行简单可靠的优化,耗时短
C2编译器:对字节码进行耗时较长的优化,以及激进优化
优化策略
C1
- 方法内联:把目标方法的代码原封不动地“复制”到发起调用的方法之中,避免发生真实的方法调用
- 去虚拟化:对唯一的实现进行内联
- 余消除:在运行期间把一些不会执行的代码折叠掉
C2
- 标量替换:用标量值代替聚合对象的属性
- 栈上分配:对于未逃逸的对象分配对象在栈,而不是堆
- 同步消除:消除同步操作,通常指synchronized
8. 分层编译策略
程序解释执行时,即可以不开启性能监控触发C1编译器,也可以开启性能监控触发C2编译器。这两种编译器相互协作共同来执行编译任务,就叫分层编译策略
9. 展望:Graal编译器和AOT编译器
Graal编译器:从jdk10加入了的全新的即时编译器,目前还在实验阶段
AOT编译器jaotc:静态提前编译器,在程序运行之前进行编译
AOT编译器
优点:
不必等待即时编译器的预热,减少java应用给人带来“第一次运行慢”的不良体验
缺点:
破坏了“一次编译,到处运行”
降低了java链接过程的动态性,加载的代码在编译期就必须全部已知