初探GraalVM(初探罗特斯)
JAVA老态渐显
人们一开始被JAVA语言的"write once, run anywhere"特性所吸引,后来变成离不开JAVA繁荣的生态。但作为一门发展了快30年的编程语言,近些年来,在云原生的趋势下,JAVA优点逐渐变成大家都有,而缺陷却愈发明显。
比如.NET的开源使得多了虚拟机,也可以一次编写、到处运行。另外,随着容器化的流行,"build once, run anywhere"逐渐深入人心,可以认为各种语言都具备跨平台的能力了。由于云原生基础设施大多由go和rust语言开发,go和rust也越来越流行。
JAVA被诟病体积大、启动缓慢、占用内存多、执行速度不是很快等等。
GraalVM是什么
简单地说,GraalVM是一个能在多种CPU架构上支持多种操作系统,将多种编程语言源代码编译成本地代码的编译工具。
硬件上,主要是支持ARM64和x86_64。操作系统上,支持主流的Windows、Linux、MacOS。编程语言上,支持Java、JavaScript、Python、Ruby、R、wasm等,而且也支持他们的互相调用。
GraalVM如何使用
GraalVM目前只支持64位架构的CPU,包括amd64(也有称之为x84_64的)和aarch64(也有称之为arm64的)。
同时,操作系统也必须是64位的,官方支持的操作系统有Linux、Windows、MacOS。
另一方面,JDK的版本支持JDK8、JDK11、JDK17。
支持的组合如下:
# https://www.oracle.com/downloads/graalvm-downloads.html?selected_tab=1
graalvm-ee-jdk8-linux-*.tar.gz
graalvm-ee-jdk8-windows-*.tar.gz
graalvm-ee-jdk8-darwin-*.tar.gz
# https://github.com/graalvm/graalvm-ce-builds/releases
graalvm-ce-jdk11-linux-amd64-*.tar.gz
graalvm-ce-jdk11-linux-aarch64-*.tar.gz
graalvm-ce-jdk11-darwin-amd64-*.tar.gz
graalvm-ce-jdk11-windows-amd64-*.tar.gz
graalvm-ce-jdk17-linux-amd64-*.tar.gz
graalvm-ce-jdk17-linux-aarch64-*.tar.gz
graalvm-ce-jdk17-darwin-amd64-*.tar.gz
graalvm-ce-jdk17-windows-amd64-*.tar.gz
GraalVM支持使用JVMCI将代码编译成字节码,也支持将字节码再编译成原生镜像:
# 编译成字节码
cd src/main/java/
javac p/k/g/Klazz.java
# 安装原生镜像编译工具
gu install native-image
# 如果是EE版本,使用"gu -L install ${user.home}/Downloads/native-image-installable-svm-svmee-${java.version}-${os}-${arch}-${version}.jar"
# 查看安装是否成功(出现native-image则成功)
gu list
# 安装编译工具(Linux为GCC、Windows可以安装Visual Studio)
## redhat/centos等rpm系列,使用如下命令:
sudo dnf install gcc glibc-devel zlib-devel libstdc++-static
## debian/ubuntu等deb系列,使用如下命令:
sudo apt-get install build-essential libz-dev zlib1g-dev
# Windows系统报错:
# Error: Default native-compiler executable 'cl.exe' not found via environment variable PATH
# Error: To prevent native-toolchain checking provide command-line option -H:-CheckToolchain
# com.oracle.svm.core.util.UserError$UserException: Default native-compiler executable 'cl.exe' not found via environment variable PATH
# 下载Visual Studio,并安装windows sdk
# 开始菜单输入“x64”,(根据VS版本,比如最新的是2022)从自动搜索结果找到“x64 Native Tools Command Prompt for VS 2022",打开该应用
# class文件必须和native-image同磁盘分区,否则报如下错误:
# Fatal error:java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: 'other' has different root
以linux下JDK17为例:
- fibonacci
先看一个较简单的java应用,,使用递归方式计算斐波那契数列。
public class Main {
public static void main(String[] args) {
long start = System.nanoTime();
int gap = 80;
if(args.length > 0) {
gap = Integer.parseInt(args[0]);
}
if(gap < 2 || gap > 80) {
throw new IllegalArgumentException("参数必须在2~80之间");
}
long total = fibonacci(gap);
// 80: 23416728348467685
// 30: 832040
System.out.println(total);
System.out.println((System.nanoTime() - start) / 1000);
}
private static long fibonacci(long gap) {
if(gap == 1L || gap == 2L) {
return 1L;
}
return fibonacci(gap - 1) + fibonacci(gap - 2);
}
}
源代码739字节,使用JDK8编译成的class只有999字节,编译成本地代码后大概16M(16275248)。
整个的编译耗时约22秒,内存使用最高接近5G,过程信息如下:
[root@localhost ~]# $JAVA_HOME/bin/native-image Main
[main:80299] classlist: 1,477.90 ms, 0.96 GB
[main:80299] (cap): 318.30 ms, 0.96 GB
[main:80299] setup: 1,514.49 ms, 0.96 GB
[main:80299] (clinit): 100.39 ms, 2.36 GB
[main:80299] (typeflow): 1,440.80 ms, 2.36 GB
[main:80299] (objects): 2,625.83 ms, 2.36 GB
[main:80299] (features): 1,048.63 ms, 2.36 GB
[main:80299] analysis: 5,625.17 ms, 2.36 GB
[main:80299] universe: 486.45 ms, 2.36 GB
[main:80299] (parse): 425.09 ms, 2.36 GB
[main:80299] (inline): 674.63 ms, 2.37 GB
[main:80299] (compile): 9,235.29 ms, 4.61 GB
[main:80299] compile: 11,133.33 ms, 4.61 GB
[main:80299] image: 859.84 ms, 4.61 GB
[main:80299] write: 333.49 ms, 4.61 GB
[main:80299] [total]: 21,592.56 ms, 4.61 GB
[root@localhost ~]# ll
-rwxrwxr-x. 1 root root 16275248 12月 26 10:58 main
-rw-rw-r--. 1 root root 19 12月 26 10:58 main.build_artifacts.txt
-rwxrwxrwx. 1 root root 999 12月 25 21:49 Main.class
从运行时间上看,本地代码略优于字节码。内存占用上,本地代码也是优于字节码的。而在CPU使用率上,两者基本没有差别。
由于程序不涉及网络或磁盘开销,此处就不做比较。
各执行3次汇总数据对比如下:
类型 | 次序 | 耗时(ms) | 最大使用内存(kb) | 最大CPU使用率 |
字节码 | 1 | 21605 | 11776 | 4% |
本地代码 | 2 | 18793 | 12284 | 4% |
本地代码 | 3 | 18799 | 1192 | 5% |
本地代码 | 4 | 18796 | 2376 | 5% |
字节码 | 5 | 22063 | 16008 | 5% |
字节码 | 6 | 22055 | 17904 | 5% |
第一次使用graalvm的jdk17运行,先启动vmstat,后启动应用,详细数据如下:
[root@localhost ~]# vmstat -t -w 1 100
procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu-------- -----timestamp-----
r b swpd free buff cache si so bi bo in cs us sy id wa st CST
0 0 0 13277820 3788 1402632 0 0 25 1 33 24 2 0 98 0 0 2021-12-28 16:10:13
1 0 0 13260128 3788 1404684 0 0 0 0 2097 2718 3 0 97 0 0 2021-12-28 16:10:14
1 0 0 13269760 3788 1395092 0 0 0 0 1284 373 6 0 94 0 0 2021-12-28 16:10:15
1 0 0 13269760 3788 1395092 0 0 0 36 1317 404 6 0 94 0 0 2021-12-28 16:10:16
1 0 0 13271704 3788 1393148 0 0 0 0 1237 296 6 0 94 0 0 2021-12-28 16:10:17
1 0 0 13271704 3788 1393148 0 0 0 0 1283 305 6 0 94 0 0 2021-12-28 16:10:18
1 0 0 13271704 3788 1393148 0 0 0 0 1239 293 6 0 94 0 0 2021-12-28 16:10:19
1 0 0 13271232 3788 1393024 0 0 0 0 1282 311 6 0 94 0 0 2021-12-28 16:10:20
1 0 0 13271232 3788 1393024 0 0 0 16 1368 363 6 0 94 0 0 2021-12-28 16:10:21
1 0 0 13271252 3788 1393040 0 0 0 0 1408 364 6 0 94 0 0 2021-12-28 16:10:22
1 0 0 13271252 3788 1393040 0 0 0 0 1249 310 6 0 94 0 0 2021-12-28 16:10:23
1 0 0 13271232 3788 1393040 0 0 0 0 1279 318 6 0 94 0 0 2021-12-28 16:10:24
1 0 0 13271232 3788 1393040 0 0 0 0 1214 246 6 0 94 0 0 2021-12-28 16:10:25
1 0 0 13271232 3788 1393040 0 0 0 8 1279 250 6 0 94 0 0 2021-12-28 16:10:26
1 0 0 13271224 3788 1393036 0 0 0 0 1619 504 6 0 94 0 0 2021-12-28 16:10:27
1 0 0 13271224 3788 1393036 0 0 0 0 1184 220 6 0 94 0 0 2021-12-28 16:10:28
1 0 0 13271224 3788 1393036 0 0 0 0 1175 218 6 0 94 0 0 2021-12-28 16:10:29
1 0 0 13271224 3788 1393036 0 0 0 2 1177 219 6 0 94 0 0 2021-12-28 16:10:30
1 0 0 13271224 3788 1393036 0 0 0 12 1295 302 6 0 94 0 0 2021-12-28 16:10:31
1 0 0 13271224 3788 1393036 0 0 0 0 1175 202 6 0 94 0 0 2021-12-28 16:10:32
1 0 0 13271224 3788 1393036 0 0 0 0 1176 232 6 0 94 0 0 2021-12-28 16:10:33
2 0 0 13266044 3788 1398152 0 0 0 0 1440 311 6 0 94 0 0 2021-12-28 16:10:34
1 0 0 13266060 3788 1398140 0 0 0 0 1262 316 6 0 94 0 0 2021-12-28 16:10:35
0 0 0 13284332 3788 1395020 0 0 0 4 1042 677 2 0 98 0 0 2021-12-28 16:10:36
0 0 0 13284332 3788 1395020 0 0 0 0 191 255 0 0 100 0 0 2021-12-28 16:10:37
0 0 0 13277880 3788 1401448 0 0 0 0 1465 1948 0 0 100 0 0 2021-12-28 16:10:38
[root@localhost ~]# date && $JAVA_HOME/bin/java Main 50 && date
2021年 12月 28日 星期二 16:10:14 CST
12586269025
21605582
2021年 12月 28日 星期二 16:10:35 CST
第二次使用本地代码,同样先启动vmstat,然后启动应用,详细数据如下:
[root@localhost ~]# vmstat -t -w 1 100
procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu-------- -----timestamp-----
r b swpd free buff cache si so bi bo in cs us sy id wa st CST
0 0 0 13121080 6960 1462068 0 0 22 1 36 31 1 0 98 0 0 2021-12-28 16:17:03
1 0 0 13102800 6960 1480164 0 0 15896 12 1985 2325 2 0 98 0 0 2021-12-28 16:17:04
1 0 0 13108916 6960 1473508 0 0 0 4 1311 361 6 0 94 0 0 2021-12-28 16:17:05
1 0 0 13108916 6960 1473508 0 0 0 0 1350 303 6 0 94 0 0 2021-12-28 16:17:06
1 0 0 13110988 6960 1471424 0 0 0 0 1307 369 6 0 94 0 0 2021-12-28 16:17:07
1 0 0 13110988 6960 1471424 0 0 0 0 1239 285 6 0 94 0 0 2021-12-28 16:17:08
1 0 0 13111016 6960 1471440 0 0 0 0 1245 356 6 0 94 0 0 2021-12-28 16:17:09
1 0 0 13111016 6960 1471440 0 0 0 4 1267 296 6 0 94 0 0 2021-12-28 16:17:10
1 0 0 13111016 6960 1471440 0 0 0 0 1449 373 6 0 94 0 0 2021-12-28 16:17:11
1 0 0 13111016 6960 1471440 0 0 0 0 1313 279 6 0 94 0 0 2021-12-28 16:17:12
1 0 0 13111016 6960 1471440 0 0 0 0 1293 309 6 0 94 0 0 2021-12-28 16:17:13
1 0 0 13111016 6960 1471440 0 0 0 0 1265 300 6 0 94 0 0 2021-12-28 16:17:14
1 0 0 13110988 6960 1471436 0 0 0 0 1531 436 6 0 94 0 0 2021-12-28 16:17:15
2 0 0 13110996 6960 1471436 0 0 0 0 1246 237 6 0 94 0 0 2021-12-28 16:17:16
1 0 0 13110996 6960 1471436 0 0 0 0 1211 228 6 0 94 0 0 2021-12-28 16:17:17
1 0 0 13110996 6960 1471436 0 0 0 0 1178 200 6 0 94 0 0 2021-12-28 16:17:18
1 0 0 13110996 6960 1471436 0 0 0 0 1200 234 6 0 94 0 0 2021-12-28 16:17:19
1 0 0 13110988 6960 1471432 0 0 0 8 1225 235 6 0 94 0 0 2021-12-28 16:17:20
1 0 0 13110988 6960 1471432 0 0 0 0 1279 272 6 0 94 0 0 2021-12-28 16:17:21
1 0 0 13110988 6960 1471432 0 0 0 0 1185 220 6 0 94 0 0 2021-12-28 16:17:22
1 0 0 13108796 6960 1473504 0 0 0 0 1128 495 4 0 96 0 0 2021-12-28 16:17:23
0 0 0 13106016 6960 1476740 0 0 0 0 329 464 0 0 100 0 0 2021-12-28 16:17:24
[root@localhost ~]# date && ./main 50 && date
2021年 12月 28日 星期二 16:17:04 CST
12586269025
18793224
2021年 12月 28日 星期二 16:17:23 CST