11 晚期(运行期)优化

Wu Jun 2020-01-09 20:44:20
05 Java > 01 Java 虚拟机

1 HotSpot 虚拟机内的即时编译器

1.1 解释器与编译器

当程序需要迅速启动和执行的时候,解释器可以先发挥作用,省去编译的时间立即执行;在程序运行后,随着时间的推移,编译器把越来越多的代码编译成本地代码提升执行效率

1)运行模式

HotSpot虚拟机中内置了两个即时编译器,分别为Client Compiler和Server Compiler,或简称为C1编译器和C2编译器;虚拟机会根据自身版本与宿主机器的硬件性能自动选择运行模式,也可以使用“-client”或“-server”参数去强制指定运行模式;

2)分层编译

想要编译出优化程度更高的代码,解释器可能还要替编译器收集性能监控信息,为了在程序启动响应速度与运行效率之间达到最佳平衡,HotSpot 虚拟机还会逐渐启动分层编译的策略:第 0 层,程序解释运行;第 1 层,C1 编译;第 2 层,C2 编译;

实施分层编译后,Client Compiler 和 Server Compiler 将会同时工作,许多代码都可能会被多次编译,用 Client Compiler 获取更高的编译速度,用 Server Compiler 来获取更好的编译质量,在解释执行的时候也无须再承担性能收集监控信息的任务;

1.2 编译对象与触发条件

1)热点代码

被 JIT 编译的热点代码有两类:被多次调用的方法、被多次执行的循环体;

2)热点探测

基于采样的热点探测和基于计数器的热点探测,在 HotSpot 虚拟机中使用的是第二种,通过方法计数器和回边计数器进行热点探测。

方法调用计数器触发的即时编译交互过程如下图所示:

image

1.3 编译过程

1)Client Compiler

对于 Client Compiler 来说,它是一个简单快速的三段式编译器,主要的关注点在于局部性的优化,而放弃了很多耗时较长的全局优化手段;

其大致过程如下所示:

image

2)Server Compiler

Server Compiler 是专门面向服务端的典型应用并为服务端的性能配置特别调整过的编译器,也是一个充分优化过的高级编译器,几乎能达到 GNU C++ 编译器使用 -02 参数时的优化强大,它会执行所有经典的优化动作,如无用代码消除、循环展开、循环表达式外提、消除公共子表达式、常量传播、基本块重排序等,还会实现如范围检查消除、空值检查消除等 Java 语言特性密切相关的优化技术;

1.4 查看及分析即时编译结果

2 编译优化技术

2.1 优化技术概览

image image

2.2 公共子表达式消除

如果一个表达式E已经计算过了,并且从先前的计算到现在E中所有变量的值都没有发生变化,那么 E 的这次出现就成为了公共子表达式,只需要直接用前面计算过的表达式结果代替 E 就可以了;

2.3 数组边界检查消除

对于虚拟机的执行子系统来说,每次数组元素的读写都带有一次隐含的条件判断,对于拥有大量数组访问的程序代码无疑是一种性能负担;

2.4 方法内联

2.5 逃逸分析

逃逸分析的基本行为就是分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用(方法逃逸),甚至还可能被外部线程所访问到(线程逃逸);

如果能证明一个对象不会逃逸到方法或线程之外,则可能为这个变量进行一些高效的优化,比如栈上分配(减轻垃圾收集的压力)、同步消除(读写不会有竞争)、标量替换;