iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >「译」Graal JIT编译器是如何工作的
  • 387
分享到

「译」Graal JIT编译器是如何工作的

「译」GraalJIT编译器是如何工作的 2014-09-21 07:09:50 387人浏览 绘本
摘要

JIT编译器是什么 我敢说很多读者都知道JIT编译器是什么,但是我还是会覆盖基本概念,让在场各位都没有基础上的疑问。 当你运行javac命令,或者用IDE保存的时候就做编译,你的java程序会从java代码编译成JVM字节码。JVM字

「译」Graal JIT编译器是如何工作的

JIT编译器是什么

我敢说很多读者都知道JIT编译器是什么,但是我还是会覆盖基本概念,让在场各位都没有基础上的疑问。

当你运行javac命令,或者用IDE保存的时候就做编译,你的java程序会从java代码编译成JVM字节码。JVM字节码是Java代码的二进制形式的表示。它比起源码来说更紧凑,更简单。但是绝大多数CPU是不能直接执行JVM字节码的。

要运行java程序需要jvm解释字节码。解释字节码通常都会比运行在真正CPU上的机器代码要慢,所以JVM可以在运行时使用其他编译器,将字节码编译成你的CPU可以直接跑的机器代码。

这个编译器通常会比javac更复杂,会做很多优化来产出高质量的机器代码。

为什么JIT编译器要用Java来写

Openjdk是JVM的一个实现,现在它包含两个JIT编译器。客户端编译器,也叫C1,设计目的是编译速度要快,所以产出的代码会包含较少优化。服务器编译器,也叫opto或者C2,设计初衷是花更多的时间产出高效优化的代码。

两者的设计动机是C1适合桌面应用程序,它们不能容忍因为JIT编译导致长时间的停顿,C2适合长时间运行的服务器程序,它们可以花更多时间在编译上面。

现在的JVM将它们组合在了一起,代码首先使用C1编译,如果后面还在运行而且值得为它花费额外时间就使用C2再做编译。这个机制叫做分层编译。

让我们把目光转向C2——花更多时间在优化上面

我们可以从GitHub克隆openjdk镜像,或者可以直接浏览它的网站下载。

$ git clone https://github.com/dmlloyd/openjdk.git

C2代码位于openjdk/hotspot/src/share/vm/opto.

首先,C2使用c++写的。当然C++没什么本质上的错误,但却有一些麻烦。C++是一门不安全的语言——这意味这C++的错误可以造成虚拟机crash。也由于代码年代久远,用C++写的C2变得很难维护,很难扩展。

C2背后的关键人物Cliff Click说他再也不会用C++写虚拟机,我们也听Twitter JVM团队说C2目前是一滩死水,亟待一个替代品,因为在它上面开发太困难了。

所以回到问题,为什么Java可以帮我们解决这些问题?呃因为上述所有需求都暗示我们用Java而不是C++。Java异常比C++ cash更安全,没有内存泄漏,没有悬空指针,也有很多工具比如调试器,profiler,visualvm,还有很多ide支持,等等。

你可能会想用Java写一个JIT编译器这怎么可能?你可能认为只有使用低级系统语言比如C++才能做到,但是在这个talk中我想说不是的,完全不是!事实上JIT编译器要做的只是接受JVM字节码然后产出机器代码——你收到一个byte[]数组然后返还一个byte[]即可。它可能背后做很多复杂的工作,但是这完全不涉及一个真的“系统”,你也不需要一个“系统”语言——一些定义认为系统语言是指类似C或者C++的语言,但不是Java。

配置graal

我们要做的第一件事是java9。graal使用的接口叫做jvmci,由JEP 243Java-Level JVM Compiler Interface提案加入到Java中。 第一个实现提案的版本是java9。我使用9+181。如果有特殊需求也可以使用backport jvmci的java8。

$ export JAVA_HOME=`pwd`/jdk9
$ export PATH=$JAVA_HOME/bin:$PATH
$ java -version
java version "9"
Java(TM) SE Runtime Environment (build 9+181)
Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)

下一步需要一个构建工具mx。 他有点像Maven或gradle,但是可能你从没在你的程序上用过它。它支持一些复杂的使用样例,但是我们只使用它做简单的构建工作。

$ git clone Https://github.com/graalvm/mx.git
$ cd mx; git checkout 7353064
$ export PATH=`pwd`/mx:$PATH

接着我们克隆graal本身。。我是用graalvm的一个版本,版本号是0.28.2

$ git clone https://github.com/graalvm/graal.git --branch vm-enterprise-0.28.2

该仓库包含了一些项目,目前我们不关心。我们可以切换到compiler子目录,那就是graal jit本身。然后使用mx构建它。

$ cd graal/compiler
$ mx build

现在我要使用eclipse ide打开graal源码。我是用eclipse 4.7.1。 mx支持生成eclipse项目文件。

$ mx eclipseinit

如果你想使用graal作为workspace,点File,Import...,General,Existing projects然后选择graal目录即可。如果你没用Java9运行eclipse本身,那你可能需要attach一个jdk。

ok,现在万事俱备,以一个简单的代为例我会展示它是如何工作的。

class Demo {
  public static void main(String[] args) {
    while (true) {
      workload(14, 2);
    }
  }

  private static int workload(int a, int b) {
    return a + b;
  }
}

我们将用javac编译,然后使用jvm运行。首先使用传统的C2 JIT。在这之前我们加上一些参数,用-XX:+PrintCompilation jvm记录哪些方法便已过,用-XX:CompileOnly=Demo::workload让编译器只编译某个方法,免得输出太多了。

$ javac Demo.java
$ java 
  -XX:+PrintCompilation 
  -XX:CompileOnly=Demo::workload 
  Demo
...
    113    1       3       Demo::workload (4 bytes)
...

上面的log表示workload方法被编译了,其他细节信息我不做解释。

现在让我们使用刚刚构建的Graal作为Java9 JVM的JIT编译器。我们需要再加一些比较复杂的flags。

·--module-path=...和--upgrade-module-path=...把graal加入模块路径。注意模块是Jigsaw模块系统的东西,现在已经加入Java9,目前来说你可以将模块路径看成是classpath。

我们需要-XX:+UnlockExperimentalVMOptions因为JVMCI(graal使用的)现目前还是实验性质的。

然后加上-XX:+EnableJVMCI告诉JVM我们要使用JVMCI,然后加上-XX:+UseJVMCICompiler告诉jvm我们想配置一个新的JIT编译器。

接着简单起见,加上-XX:-TieredCompilation关闭分层编译让JVM只有一个JVMCI编译器而不是C1和JVMCI混合分层。

当然,前面的-XX:+PrintCompilation 和-XX:CompileOnly=Demo::workload还是保持不变。和之前一样,我们会看到有一个方法被编译了虽然是使用graal编译的。现在请只管跟着我做。

$ java 
  --module-path=graal/sdk/mxbuild/modules/org.graalvm.graal_sdk.jar:graal/truffle/mxbuild/modules/com.oracle.truffle.truffle_api.jar 
  --upgrade-module-path=graal/compiler/mxbuild/modules/jdk.internal.vm.compiler.jar 
  -XX:+UnlockExperimentalVMOptions 
  -XX:+EnableJVMCI 
  -XX:+UseJVMCICompiler 
  -XX:-TieredCompilation 
  -XX:+PrintCompilation 
  -XX:CompileOnly=Demo::workload 
  Demo
...
    583   25             Demo::workload (4 bytes)
...

JVMCI编译器接口  郑州男科医院哪家好:http://www.ytsgnk.com/郑州看男科医院哪里好:http://www.ytsgnk.com/郑州哪个医院男科专业:http://www.ytsgnk.com/

我们现在做的很牛逼了不是吗?我们有个JVM,然后用新的JIT替换了之前的那个,还用它编译了代码,且没有改变JVM的任何代码。让这一切变得可能的正是JVMCI——JVM编译器接口——之前提到过JEP243提出它现在已经并入java9。

这个idea和jvm现有的一些技术其实差不多。

以前你可能用Java注解处理API添加过一些注解到javac,它们可以处理源代码。不难看出java注解就是个获取它们附着于的源代码,然后产出新源代码的工具。

你可能使用过java agent做自定义的java字节码处理。它可以拦截java字节码然后修改它。

JVMCI和它们一样。它让你可以插入一个java写的jit编译器到jvm上。

等下我会介绍ppt上展示的代码的一些方法,然后我会简化标识符和逻辑帮助你理解这个idea,接着我会切换到eclpse的一些屏幕截图向你展示真的代码,虽然可能有点复杂,但是大体上是一样的。这个talk的重要内容就是帮助你深入源码本身,所以我不想隐藏它,尽管它很复杂。

首先我想消除你觉得jit编译器极其复杂的想法。JIT编译器的输入什么?它获取要编译的方法的字节码,字节码,看名字就知道是“一个字节数组的代码”。JIT编译器输出什么?它输出方法对应的机器代码。机器代码也是“一个字节数组的代码“
所以当你写一个新jit插入到jvm的时候你要实现的接口看起来类似下面:

interface JVMCICompiler {
    byte[] compileMethod(byte[] bytecode);
}

所以你大可不必认为java怎么能做jit编译产出机器码这么底层的事情,他就是个byte[]到byte[]的函数而已。

不过实际上的比这要复杂一些。只是一个字节数组的代码还不够,我们还想要一些信息比如局部变量的个数,栈的大小,解释器收集到的profiling信息等,这让我们可以了解实际代码运行的情况。因此输入不是字节数组而是一个CompilationRequest,它可以告诉我们哪一个JavaMethod要编译,然后给我们需要的所有信息。

您可能感兴趣的文档:

--结束END--

本文标题: 「译」Graal JIT编译器是如何工作的

本文链接: https://www.lsjlt.com/news/5877.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何分析.Net Compact Framework CLR中的JIT编译器
    如何分析.Net Compact Framework CLR中的JIT编译器,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。这个.Net Compact Framework CL...
    99+
    2023-06-17
  • PHP8.0中的JIT编译器对性能的提升
    随着现代化科技的发展,计算机处理速度的要求越来越高,程序员们也在不断地探索提升程序性能的方法。作为一门广泛应用的编程语言,PHP在不断优化和升级中也加入了JIT编译器,这一举措在探索PHP性能提升的道路中起到了重要作用。什么是JIT编译器?...
    99+
    2023-05-14
    PHP 性能提升 JIT编译器
  • PHP8如何通过JIT编译提升Web应用的性能?
    PHP8如何通过JIT编译提升Web应用的性能?随着Web应用的不断发展和需求的增加,提升Web应用的性能成为了开发者关注的焦点之一。PHP作为一种常用的服务器端脚本语言,一直以来都备受开发者喜爱。而PHP8中引入了JIT(即时编译)编译器...
    99+
    2023-10-22
    性能 Web应用 PHP JIT编译
  • PHP8中如何使用JIT编译提升代码性能?
    PHP语言一直以来都被广泛用于构建Web应用程序,但是由于解释执行的特性,导致了其性能相对较低。为了提升PHP的性能,从PHP7开始引入了JIT(Just-in-Time)编译器,而在全新的PHP8版本中,JIT编译的功能得到了进一步的改进...
    99+
    2023-10-22
    PHP JIT编译 代码性能
  • Golang编译器工作机制揭秘
    Golang编译器工作机制揭秘 一、引言随着Golang语言在近年来的风靡,越来越多的开发者开始关注其编译器工作原理。Golang编译器是一种特殊的编译器,它采用了一系列独特的优化技术...
    99+
    2024-03-07
    机制 编译器 golang
  • 如何理解C++编译器编译功能
    如何理解C++编译器编译功能,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。下面深度讲解C++中的大规模C++编译器,C++编译器具有很强的复杂性,并且源程序的行数也是非常多...
    99+
    2023-06-17
  • 如何使用java编译器进行编译
    使用Java编译器进行编译可以通过以下步骤:1. 确保已经安装了Java Development Kit (JDK)。可以通过在命令...
    99+
    2023-09-06
    java
  • openSUSE如何配置编译内核收尾工作
    这篇文章将为大家详细讲解有关openSUSE如何配置编译内核收尾工作,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。内核已经编译安装完成了,已经在 grub 开始菜单最下面添加了一个启动项。重启可以尝试新内...
    99+
    2023-06-16
  • 如何在PHP8中使用JIT编译提升代码执行效率?
    如何在PHP8中使用JIT编译提升代码执行效率?摘要:PHP语言一直以来以其简单易用和广泛应用而备受开发者青睐,但其执行效率一直被人诟病。然而,随着PHP8版本的发布,引入了JIT(Just-in-Time)编译器,为PHP的性能带来了巨大...
    99+
    2023-10-22
    PHP JIT编译 代码执行效率
  • 如何通过PHP8的JIT编译提升大型项目的执行速度?
    如何通过PHP8的JIT编译提升大型项目的执行速度?摘要:PHP8引入了Just-In-Time(JIT)编译器,为开发人员提供了一种提升性能的新工具。本文将探讨如何利用PHP8的JIT编译器来优化大型项目的执行速度,并提供具体的代码示例。...
    99+
    2023-10-22
    大型项目 PHP JIT编译 执行速度
  • 使用PHP8的JIT编译器:优化你的应用程序性能
    利用PHP8的JIT编译器:提高你的应用程序效率 随着Web应用程序的迅猛发展,对于效率的要求也越来越高。而PHP作为一种广泛使用的服务器端编程语言,其性能一直备受争议。然而,PHP8的最新发布引入了一项重大改进 - 即Just...
    99+
    2024-01-26
    PHP JIT编译器 应用程序效率
  • ubuntu交叉编译工具如何安装
    要安装Ubuntu的交叉编译工具,您可以按照以下步骤进行操作:1. 打开终端窗口。2. 更新软件包列表,运行以下命令:sudo ap...
    99+
    2023-09-20
    ubuntu
  • Golang编译器选型指南:如何选择适合你的编译器?
    随着Golang的日益流行,越来越多的开发者开始选择使用它进行编程。然而,选择哪个Golang编译器却成为了一个问题。在这篇文章中,我们将讨论如何选择适合你的Golang编译器。 首先,让我们介绍一下Gola...
    99+
    2024-01-19
    选型指南 适合编译器
  • 如何定制Go编译器
    这篇文章主要介绍“如何定制Go编译器”,在日常操作中,相信很多人在如何定制Go编译器问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何定制Go编译器”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!01 Ub...
    99+
    2023-06-15
  • Docker容器如何编译LNMP
    这篇文章主要讲解了“Docker容器如何编译LNMP”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Docker容器如何编译LNMP”吧!一、 项目描述使用Docker容器基于centos镜像...
    99+
    2023-06-22
  • c++编译器如何使用
    要使用C++编译器,你需要按照以下步骤进行操作:1. 安装编译器:首先,你需要安装一个C++编译器。常见的C++编译器包括GCC、C...
    99+
    2023-09-08
    c++
  • linux编译器如何打开
    在Linux系统中,打开编译器可以通过以下几种方式: 命令行方式:在终端中输入编译器的可执行文件名,如gcc(C语言编译器)、g...
    99+
    2024-02-29
    linux
  • ubuntu如何用vi编译器
    ubuntu使用vi编译器的示例:比如使用vi编译器编辑c++代码。打开终端,输入以下命令编辑hello.cpp文件。vim hello.cpp输入如下代码:#include using namespace std;int main(){c...
    99+
    2024-04-02
  • vue工程编译sass错误如何解决
    这篇文章主要介绍了vue工程编译sass错误如何解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vue工程编译sass错误如何解决文章都会有所收获,下面我们一起来看看吧。vue工程编译sass错误的解决办法:...
    99+
    2023-07-04
  • go编译器是否会编译main中从未使用过的包
    php小编草莓很高兴为大家解答关于go编译器是否会编译main中从未使用过的包的问题。在go语言中,编译器不会编译未使用的包。这是因为go语言的设计理念是简洁高效,不会浪费时间和资源去...
    99+
    2024-02-09
    go语言
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作