简介
GraalVM是一个高性能的JDK,它能加速Java应用的执行速度,同时为其他语言提供运行环境,如JavaScript、Python、Rust等等。官网
新的技术总是会给我们契机去了解这个领域内技术的发展,GraalVM能带领我们去走进虚拟机与编译器。
GraalVM的特点
借鉴
-
加快Java应用的启动
GraalVM能将Java应用的启动时间减少到1/50
-
节省内存
GraalVM能减少4/5的内存
-
节省硬盘
GraalVM能将docker镜像的大小降低70%
-
多语言支持,统一语言工具链
不仅可以运行Java,还可以运行js、ruby、python等语言,可以用统一的语言进行调试;
Java代码可以无缝调用其他语言的功能和三方库
前3点的特性感觉就是为解决Java上云的,基本解决了Java上云占用资源过多的问题,这也是Spring Native的初衷吧
虚拟机的进化
参考Java代码的执行过程:
对于CPython,R,Ruby,PHP乃至自己写的一门新的语言,回顾一下我们的一般做法:
-
首先解析源代码到AST,然后写一个AST解释器执行代码
-
当有些人用这个语言的时候,语言设计者可能继续迭代,实现一个虚拟机,包括GC,运行时等,代码执行仍然是AST解释器
-
用的人多了,继续迭代,将AST转换为字节码,使用字节码解释器
-
用的人特别多,性能也很关键,如果这个语言社区有足够资金和人力,那么可以写JIT编译器,提升GC性能等,大部分语言都到不了这一步。
借鉴
我不太看好其他语言运行于GraalVM之上,因为其他语言成熟的虚拟机如v8引擎本来就很优秀了,没必要往这个上搬,只能为一些不太优秀的提供一个路径,主要是服务Java语言,能用Java调用其他语言。
GraalVM的结构
https://www.zhihu.com/question/28927570/answer/2058826630
JIT编译器
JIT编译器是JVM的一部分,负责把字节码编译成机器码然后执行。
具体到hotsport虚拟机,叫做c1、c2编译器
JVMCI
Java9之后提供的一个接口,全称是JVM Compiler interface,java虚拟机编译器接口,提供可以插拔的编译器接口。也就是说Java虚拟机提供了一个允许用户自定义JIT编译器的接口,可以用来替代C2. 这样就有了Graal JIT,上图中就是这个意思,用Graal JIT替换了C2 JIT的hotspot虚拟机。
Graal Compiler
跟用c++编写的c2编译器不一样,graal编译器是由java编写而成的。
graal既然能做到jit,同样也能实现aot,aot是什么?
jit是先通过javac将源码编译成字节码,然后再在运行时,由jvm里面的jit编译器,将字节码编译成机器码以执行的过程;
aot是在编译的时候,直接将源代码编译成机器码的过程;aot在编译的时候,直接将源代码编译成机器代码,然后将其打包成目标平台的格式,这个工具在graal中叫做native image。生成的机器码格式里面,没有完整的jvm,但是有一些用于支持其运行的组件,被称为substrate vm(基层虚拟机)。

也正是这个原因,所以才有了之前提到的特点。
Truffle
动态脚本语言,如python、JavaScript等,本身就不需要编译,都是解释执行,这跟aot的过程是类似的,所以graalvm就做了一个转换接口,将这些脚本语言翻译成graal认识的格式,这就是Truffle干的事。
目前这一部分,只适用于比较简单的语言,如python、js等语言估计需要很多的工作。
另外:既然从java上这条路能走通,从其他语言JIT应该也能走通。
GraalVM的使用
参考
下载与安装
-
下载,官方地址,当前最新是:22.3.0
-
解压
-
修改环境变量
# 修改/etc/profile
export JAVA_HOME=/path/to/graalvm
export PATH=/path/to/graalvm:$PATH
# 生效
source /etc/profile
-
确定是否成功
java -version
初步应用
-
利用gu下载native-image
gu类似于pip、npm等工具
sudo gu install native-image
-
HelloWorld.java代码
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
-
编译与打包
javac HelloWorld.java
native-image HelloWorld
这个要注意$CLASSPATHexport CLASSPATH=.:${JAVA_HOME}/lib:${JAVA_HOME}/jre/lib
,要有.
,否则找不到类。
执行完成之后,在目录下生成HelloWorld启动程序。
-
运行
./HelloWold
IDEA中使用
现在用的插件是native-maven-plugin,官方文档](https://graalvm.github.io/native-build-tools/latest/maven-plugin.html)
-
创建Spring Initializr工程
-
添加GraalVM NativeSupport
-
增加native-maven-plugin插件
-
添加测试代码
-
使用插件打包mvn spring-boot:build-image
经过几次尝试,一直显示启动不了,显示:Could not find class xxx_ApplicationContextInitializer
,后来选择mvn的profile后,问题解决
这里要注意mvn的profile要选择native
mvn clean package -Pnative -DskipTests
mvn的profile与spring的profile差异:https://www.cnblogs.com/sandyflower/p/11600058.html
-
打native的docker镜像
这里暂时先使用spring-boot-maven-plugin,通过mvn spring-boot:build-image来打包
docker run --rm -p 8081:8081 demo:0.0.1-SNAPSHOT