内容简介:在本教程中,我们将深入研究名为Graal的新Java实时(JIT)编译器。让我们首先解释JIT编译器的作用。当我们编译Java程序时(例如,使用 javac命令),我们最终将源代码编译成代码的二进制表示 - 一个JVM字节码。这个字节码比我们的源代码更简单,更紧凑,但我们计算机中的传统处理器无法执行它。
在本教程中,我们将深入研究名为Graal的新 Java 实时(JIT)编译器。
让我们首先解释JIT编译器的作用。
当我们编译Java程序时(例如,使用 javac命令),我们最终将源代码编译成代码的二进制表示 - 一个JVM字节码。这个字节码比我们的源代码更简单,更紧凑,但我们计算机中的传统处理器无法执行它。
为了能够运行Java程序,JVM解释字节码。由于解释器通常比在真实处理器上执行的本机代码慢得多,因此 JVM可以运行另一个编译器,该编译器现在将我们的字节码编译成可由处理器运行的机器代码。这种所谓的即时编译器比javac编译器复杂得多,它运行复杂的优化以生成高质量的机器代码。
Oracle的JDK实现基于开源OpenJDK项目。这包括从Java 1.3版开始提供的HotSpot虚拟机。它包含两个传统的JIT编译器:客户端编译器,也称为C1和服务器编译器,称为opto或C2。
C1设计为运行速度更快,产生的优化代码更少,而另一方面,C2需要更多的时间来运行,但产生更好的优化代码。客户端编译器更适合桌面应用程序,因为我们不希望长时间暂停JIT编译。对于可能在编译上花费更多时间的长时间运行的服务器应用程序,服务器编译器更好。
1. 分层编译
Java安装在正常程序执行期间使用两个JIT编译器。
正如我们前面提到的,由javac编译的Java程序以解释模式开始执行。JVM跟踪每个经常调用的方法并编译它们,为此,它使用C1进行编译;但是,HotSpot仍然关注这些方法的未来调用。如果调用次数增加,JVM将再次重新编译这些方法,但这次使用C2。
这是HotSpot使用的默认策略,称为分层编译。
2.服务器编译器
现在让我们关注C2,因为它是两者中最复杂的。C2已经过极度优化,可生成可与C ++竞争或更快的代码。服务器编译器本身是用C ++的特定方言编写的。
但是,它带来了一些问题。由于C ++中可能存在分段错误,因此可能导致VM崩溃。此外,在过去几年中,编译器没有实现重大改进。C2中的代码变得难以维护,因此我们无法期望使用当前设计进行新的主要增强。考虑到这一点,新的JIT编译器正在名为GraalVM的项目中创建。
GraalVM
Project GraalVM 是Oracle创建的一个研究项目,目标是完全替换HotSpot。我们可以将Graal视为几个连接项目:HotSpot的新JIT编译器和新的多语言虚拟机。它提供了一个全面的生态系统,支持大量语言(Java和其他基于JVM的语言; JavaScript,Ruby,Python,R,C / C ++和其他基于LLVM的语言)。
我们当然会关注Java。
1. Graal - 用Java编写的JIT编译器
Graal是一个高性能的JIT编译器。 它接受JVM字节码并生成机器代码。
在Java中编写编译器有几个关键优势。首先,安全,意味着没有崩溃,但异常反而没有真正的内存泄漏。此外,我们将获得良好的IDE支持,我们将能够使用调试器或分析器或其他方便的工具。此外,编译器可以独立于HotSpot,它可以生成更快的JIT编译版本。
Graal编译器的创建考虑了这些优点。 它使用新的JVM编译器接口--JVMCI与VM通信。要启用新JIT编译器,我们需要在从命令行运行Java时设置以下选项:
-XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseJVMCICompiler
这意味着我们可以用三种不同的方式运行一个简单的程序:使用常规的分层编译器,使用Java 10上的JVMCI版本或GraalVM本身。
2. JVMCI:JVM编译器接口
自JDK 9以来,JVMCI是OpenJDK的一部分,因此我们可以使用任何标准的OpenJDK或Oracle JDK来运行Graal。
JVMCI实际允许我们做的是排除标准的分层编译并插入我们全新的编译器(即Graal),而无需更改JVM中的任何内容。
界面非常简单。当Graal编译一个方法时,它会传递该方法的字节码作为JVMCI的输入。作为输出,我们将获得编译的机器代码。输入和输出都只是字节数组:
<b>interface</b> JVMCICompiler {
byte[] compileMethod(byte[] bytecode);
}
在现实场景中,我们通常需要更多信息,例如局部变量的数量,堆栈大小以及从解释器中的分析中收集的信息,以便我们知道代码在实践中如何运行。
本质上,当调用 JVMCICompiler 接口的 compileMethod()时 ,我们需要传递 CompilationRequest 对象。然后它将返回我们想要编译的Java方法,在该方法中,我们将找到所需的所有信息。
3. Graal本身
Graal本身由VM执行,所以它首先被解释并在它变热时进行JIT编译。让我们看一个例子,也可以在 GraalVM的官方网站上找到 。编译这个例子:
javac CountUppercase.java java -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseJVMCICompiler
输出:
1 (1581 ms)
2 (480 ms)
3 (364 ms)
4 (231 ms)
5 (196 ms)
6 (121 ms)
7 (116 ms)
8 (116 ms)
9 (116 ms)
total: 59999994 (3436 ms)
我们可以看到一开始需要更多时间。预热时间取决于各种因素,例如应用程序中的多线程代码量或VM使用的线程数。如果内核较少,则预热时间可能会更长。
如果不使用JVMCI编译器:
java -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler 1 (510 ms) 2 (375 ms) 3 (365 ms) 4 (368 ms) 5 (348 ms) 6 (370 ms) 7 (353 ms) 8 (348 ms) 9 (369 ms) total: 59999994 (4004 ms)
可以缩短初始时间。
Ahead-of-Time编译器模式
我们也可以在Java 10中的Ahead-of-Time编译器模式中使用Graal编译器。正如我们已经说过的那样,Graal编译器是从头开始编写的。它符合一个新的干净界面JVMCI,它使我们能够将它与HotSpot集成。
使用方法是使用配置文件驱动的方法来仅编译热方法,但我们也可以使用Graal在脱机模式下对所有方法进行全面编译而不执行代码。这是所谓的“Ahead-of-Time Compilation”, JEP 295, 但我们不会深入研究AOT编译技术。
我们以这种方式使用Graal的主要原因是为了加快启动时间,直到HotSpot中的常规分层编译方法可以接管为止。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- LLVM接受NVIDIA的“f18” Fortran编译器作为官方Fortran编译器
- 编译原理实战入门:用 JavaScript 写一个简单的四则运算编译器(四)结语
- Scala.js 0.6.29 发布,将 Scala 编译成 js 的编译器
- Go 编译器介绍
- Go 编译器介绍
- C++编译器优化
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Trading and Exchanges
Larry Harris / Oxford University Press, USA / 2002-10-24 / USD 95.00
This book is about trading, the people who trade securities and contracts, the marketplaces where they trade, and the rules that govern it. Readers will learn about investors, brokers, dealers, arbit......一起来看看 《Trading and Exchanges》 这本书的介绍吧!