官网: https://www.graalvm.org/
Github:https://github.com/oracle/graal
我是在看《深入理解java虚拟机第三版》的时候了解到的GraalVM,在书中的1.5 展望java技术的未来和11.5实战:深入理解Graal编译器有提到,感觉这玩意挺有意思的,是目前的java黑科技,大家可以去看看,这里做个学习笔记记录记录
看官网的标语是Run Programs Faster Anywhere,以更快的速度运行程序,体现出了它的高性能和蓬勃的野心。
GraalVM 是一个高性能的、支持多种编程语言的执行环境,可以显著提高应用程序的性能和效率,是微服务的理想选择。可以基于它的多语言引擎运行其他的比如(JavaScript, Python, Ruby, R, C,C++, Rust等)语言,还可以通过 AOT(Ahead-Of-Time)编译成可执行文件单独运行(通过SubstrateVM)
主要的特点:
1、底层基于Hotspot
2、通过JVMCI,基于Graal compiler实现的JIT编译器
3、打包为平台相关的可执行文件
4、跨语言全栈虚拟机,基于Truffle框架实现,可以不同语言相互调用代码
这个整体叫做GraalVM, GraalVM并不是一个新的语言虚拟机,GraalVM是指以Java hotspot虚拟机为基础,以Graal即时编译器为核心,以能运行多种语言为目标,包含一系列框架和技术的大杂烩
GraalVM Native Image是由Oracle Labs开发的一种AOT编译器,支持基于JVM的高级语言,如Java, Scala, Clojure, Kotlin。Native Image以Java bytecode作为输入,将所有应用所需的class依赖项及runtime库打包编译生成一个单独可执行文件。具有高效的startup及较小的运行时内存开销的优势。
与传统的Java虚拟机不同,Native Image是封闭式的静态分析和编译,不支持class的动态加载,程序运行所需要的多有依赖项均在静态分析阶段完成。此外GraalVM Native Image运行在一个名为SubstrateVM的轻量级的虚拟机之上。
Native image的缺点:
1、打包之后就不能用传统的java调试工具了,要调试只能用gdb,调试过程比较复杂
2、反射需要额外的配置文件,不是很方便
3、传统的JVMTI、java agent、JMX等等功能都用不了
参考:
https://aijishu.com/a/1060000000090571
基本工作原理是将这些语言的源代码、或编译后的中间格式(比如C编译后的LLVM字节码),通过一个专门的解释器转换为能被GraalVM接受的中间表示IR,这个过程叫程序特化(Partial Evaluation)
我们知道,实现一门新编程语言传统做法是实现一个编译器,把该语言编写的程序转换成可直接在硬件上运行的机器码,编译器分为前端和后端:前端负责词法分析、语法分析、类型检查和中间代码生成,后端负责编译优化和目标代码生成。一种比较取巧的做法则是将新语言编译成某种已知语言,或者已知的中间形式,例如将 Scala、Kotlin 编译成 Java 字节码。
Truffle 是一个用 Java 写的语言实现框架。基于 Truffle 的语言实现仅需用 Java 实现词法分析、语法分析以及针对语法分析所生成的抽象语法树(Abstract Syntax Tree,AST)的解释执行器。GraalVM提供了Truffle工具集快速构建面向一种新语言的解释器,如果想支持一门新语言,实现一个具体语言的AST解释器即可,目前GraalVM能够支持多语言的原因也是实现了各种不同的解释器
实际使用上,使用gu install各种语言解释器(llvm-toolchain、python、R、Ruby)即可执行各种语言的代码
参考:
https://www.zhihu.com/question/274042223
《深入理解java虚拟机第三版—1.5.1》
https://time.geekbang.org/column/article/41582 34-36章节
我们知道,hotspot jvm 内置了两个jit编译器,分别是client compiler(C1编译器)和server compiler(C2编译器),C1用于简单优化质量低,C2进行长时间优化质量更高。从Jdk10起,hotspotVM加入了一个全新的即时编译器,Graal编译器,它也是GraalVM的即时编译器,是GraalVM高性能的基石。
在hotspotVM中Graal编译器用于替代C2编译器,因为目前C2复杂到它的作者Cliff Click 大神都不愿维护的程度。它们两者最明显的区别就是Graal 是用 Java 写的,而 C2 是用 C++ 写的。相对来说,Graal 更加模块化,也更容易开发与维护。总体来说,Graal 编译结果的性能要优于 C2
在jdk10、11中可以通过**-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler**在hotspot中启用graal编译器
从图上可以看出hotspot通过JVMCI将编译请求分发给Graal编译器,Graal编译器又通过JVMCI(JVM Compiler Interface)接口(还有个类似的叫JVMTI,那个一般在agent和debug里面用,不要记混淆了)响应jvm发出的编译请求,通过JVMCI可以动态替换JIT编译器,也可以很方便的升级Graal编译器,是个很好的解耦设计
你可能会好奇用java去编译java这种操作,其实编译大概来说就是将一段byte[]转为另一段byte[],啥语言实现都行,并且javac(前端编译器)也是java写的,关于这个操作可以看看编译器的自举。
还有疑问觉得java写的性能看起来不如C++的,实际上在充分预热情况下java中的热点代码会被JIT编译为机器码,执行速度跟C++不相上下,即便是解释执行graal也只是影响编译速度而不是影响编译结果的性能(目前在刚开始运行的过程中,Graal 编译器本身需要被即时编译,会抢占原本可用于编译应用代码的计算资源。因此,目前 Graal 编译器的启动性能会较差)。
参考:
LLVM: https://www.jianshu.com/p/1367dad95445
JVMCI:http://openjdk.java.net/jeps/243
JVMCI实战:参考《深入理解java虚拟机第三版–11.5 实战:深入理解Graal编译器》
Graal介绍:https://time.geekbang.org/column/article/41245
安装sdkman
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
常用命令
sdk ls java // 列出可用版本
sdk install java 13.0.1.hs-adpt // 安装指定版本
sdk default java 11.0.5.hs-adpt // 切换默认版本
sdk use java 8.0.232.hs-adpt // 切换临时版本
sdk current java // 查看当前版本
sdk uninstall java 11.0.5.hs-adpt // 移除
sdk flush candidates // 刷新候选者
除了JDK之外,SDKMAIN!还可以安装其它Java相关的SDK,包括Scala、Kotlin、Groovy、Spring Boot、Maven、sbt和Gradle等。比如,下面的命令可以列出来全部的Maven版本。再使用sdk install maven进行安装即可。
sdk ls maven
#安装graal
sdk install 20.3.0.r8-grl
#使用gu安装native-image
gu list
gu install native-image
这个sdkman用起来确实很方便,看很多文档都有推荐这个,但是网络太差需要搭梯子,所以推荐下面的方法
https://github.com/graalvm/graalvm-ce-builds/releases
git上下载最新版本,现在推荐用jdk 11
tar zxvf graalvm-ce-java11-linux-amd64-20.3.0.tar.gz
然后解压,修改环境变量,就可以了,注意这个设置是临时生效的
export PATH=/home/graal/graalvm-ce-java11-20.3.0/bin:$PATH
export JAVA_HOME=/home/graal/graalvm-ce-java11-20.3.0
export GRAALVM_HOME=/home/graal/graalvm-ce-java11-20.3.0
最后不要忘记装这个插件
gu install native-image
安装native-image需要网络环境,如果不行可以手工下载安装
参考https://www.graalvm.org/reference-manual/graalvm-updater/#manual-installation
下载地址https://www.oracle.com/downloads/graalvm-downloads.html
选择对应的平台版本下载即可,文件大概为:native-image-installable-svm-svmee-java11-linux-amd64-20.3.0.jar
下载好后输入命令安装即可
gu -L install native-image-installable-svm-java11-darwin-amd64-20.0.1.jar
最后如果想体验各种语言在GraalVM上跑,参考https://www.graalvm.org/docs/getting-started/#start-running-applications
这里重点介绍构建native应用
下一节: Quarkus云原生应用初体验