首页IT科技jvm中gc算法(过两年 JVM 可能就要被 GraalVM 替代了)

jvm中gc算法(过两年 JVM 可能就要被 GraalVM 替代了)

时间2025-06-20 20:32:24分类IT科技浏览4933
导读:大家好,我是风筝,公众号「古时的风筝」,专注于 Java技术 及周边生态。...

大家好             ,我是风筝                   ,公众号「古时的风筝」      ,专注于 Java技术 及周边生态             。

文章会收录在 JavaNewBee 中       ,更有 Java 后端知识图谱                   ,从小白到大牛要走的路都在里面                   。

今天说一说 GraalVM      。

GraalVM 是 Oracle 大力发展和想要推广的新一代 JVM             ,目前很多框架都已经渐渐支持 GraalVM 了       ,比如我们在用的 Spring 也已经推出了对 GraalVM 兼容的工具包了             。

既然说的这么厉害                   ,那么它到底是何方神圣呢                    。

GraalVM 和 JVM 的关系

既然叫做VM             ,那肯定和 JVM 有关系的吧      。JVM 全称 Java 虚拟机,我们都知道                   ,Java 程序是运行在虚拟机上的                   ,虚拟机提供 Java 运行时,支持解释执行和部分的(JIT)即时编译器             ,并且负责分配和管理 Java 运行所需的内存                   ,我们所说的各种垃圾收集器都工作在 JVM 中      。

比如 Oracle JDK             、OpenJDK       ,默认的 JVM 是 HotSpot 虚拟机             ,这是当前应用最广泛的一个虚拟机                    。我们平时见到的各种将虚拟机的书籍                   、文章      、面试题                   ,基本上都是说的 HotSpot 虚拟机             。

除此之外      ,还有一些商用       ,或者说小众的虚拟机存在                   ,比如IBM 的J9 JVM             ,商用的 Zing VM 等      。

那 GraalVM 是另一种 Java 虚拟机吗?

是       ,又不全是                   。

GraalVM 可以完全取代上面提到的那几种虚拟机                   ,比如 HotSpot             。把你之前运行在 HotSpot 上的代码直接平移到 GraalVM 上             ,不用做任何的改变,甚至都感知不到                   ,项目可以完美的运行。

但是 GraalVM 还有更广泛的用途                   ,不仅支持 Java 语言,还支持其他语言                   。这些其他语言不仅包括嫡系的 JVM 系语言             ,例如 Kotlin             、Scala                   ,还包括例如 JavaScript                    、Nodejs      、Ruby      、Python 等                   。

GraalVM 的野心不止于此      ,看上面的图             ,它的目的是搭建一个 Framework                   ,最终的目标是想要支持任何一种语言      ,无论哪种语言       ,可以共同跑在 GraalVM 上                   ,不存在跨语言调用的壁垒。

GraalVM 和JDK有什么关系

Java 虚拟机都是内置在 JDK 中的             ,比如Orcale JDK                    、OpenJDK       ,默认内置的都是 HotSpot 虚拟机             。

GraalVM 也是一种 JDK                   ,一种高性能的 JDK                   。完全可以用它替代 OpenJDK             、Orcale JDK      。

GraalVM 如何运行 Java 程序

说了半天             ,是不是还是不知道 GraalVM 到底是什么             。

GraalVM - 还包含 Graal (JIT)即时编译器,可以结合 HotSpot 使用

GraalVM – 是一种高性能 JDK                   ,旨在加速 Java 应用程序性能                   ,同时消耗更少的资源                    。

GraalVM - 是一种支持多语言混编的虚拟机程序,不仅可以运行 JVM 系列的语言             ,也可支持其他语言      。

GraalVM 提供了两种方式来运行 Java 程序      。

第一种:结合 HotSpot 使用

上面说了                   ,GraalVM 包含 Graal (JIT)即时编译器      ,自从 JDK 9u 版本之后             ,Orcale JDK 和 OpenJDK 就集成了 Graal 即时编译器                    。我们知道 Java 既有解释运行也有即时编译             。

当程序运行时                   ,解释器首先发挥作用      ,代码可以直接执行      。随着时间推移       ,即时编译器逐渐发挥作用                   ,把越来越多的代码编译优化成本地代码             ,来获取更高的执行效率                   。即时编译器可以选择性地编译热点代码       ,省去了很多编译时间                   ,也节省很多的空间             。比如多次执行的方法或者循环      、递归等。

JDK 默认使用的是 C2 即时编译器             ,C2是用C++编写的                   。而使用下面的参数可以用 Graal 替换 C2                   。

-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler

Graal 编译器是用 Java 实现的,用 Java 实现自己的编译器。Graal 基于一些假设的条件                   ,采取更加激进的方式进行优化             。采用 Graal 编译器之后                   ,对性能有会有一定的提升                   。

但是如果你还是在用 JDK8,那对不起了             ,GraalVM 的一切都用不了      。

第二种:AOT 编译本地可执行程序

这是 GraalVM 真正厉害的地方             。

AOT 提前编译                   ,是相对于即时编译而言的                    。AOT在运行过程中耗费 CPU 资源来进行即时编译      ,而程序也能够在启动的瞬间就达到理想的性能      。例如 C 和 C++语言采用的是AOT静态编译             ,直接将代码转换成机器码执行      。而 Java 一直采用的是解释 + 即时编译技术                   ,大多数情况下 Java 即时编译的性能并不比静态编译差      ,但是还是一直朝着 AOT 编译的方向努力                    。

但是 Java 对于 AOT 来说有一些难点       ,比如类的动态加载和反射调用             。

GraalVM 显然是已经克服了这些问题                   ,使用 GraalVM 可以直接将 Java 代码编译成本地机器码形态的可执行程序      。

我们目前运行 Java 一定要安装 JDK 或者 JRE 对不对             ,如果将程序直接编译成可执行程序       ,就不用在服务器上安装 JDK 或 JRE 了                   。那就是说运行 Java 代码其实也可以不用虚拟机了是吗?

GraalVM 的 AOT 编译实际上是借助了 SubstrateVM 编译框架                   ,可以将 SubstrateVM 理解为一个内嵌精简版的 JVM             ,包含异常处理,同步                   ,线程管理                   ,内存管理(垃圾回收)和 JNI 等组件             。

SubstrateVM 的启动时间非常短,内存开销非常少。用这种方式编译出的 Java 程序的执行时间可与C语言持平                   。

下图是使用即时编译(JVM运行)与 AOT (原生可执行程序)两种方式的 CPU 和内存使用情况对比             ,可以看出来                   ,AOT 方式下 CPU 和内存的使用都非常少                   。

除了运行时占用的内存少之外      ,用这种方式最终生成的可执行文件也非常小。这对于云端部署非常友好             。目前很多场景下都使用 Docker 容器的方式部署             ,打一个 Java 程序的镜像包要包含完整的 JVM 环境和编译好的 Jar 包                   。而AOT 方式可以最大限度的缩小 Docker 镜像的体积      。

缺点

好处多多                   ,当然也有一些弊端             。对于反射这种纯粹在运行时才能确定的部分      ,不可能完全通过优化编译器解决       ,只能通过增加配置的方式解决                    。麻烦是麻烦了一点                   ,但是是可行的             ,Spring Boot 2.7的版本已经支持原生镜像了       ,Spring 这种非常依赖反射的框架都可以支撑                   ,我们用起来也应该没问题      。

GraalVM 如何支持多语言

要支持多语言             ,就要说到 GraalVM 中的另一个核心组件 Truffle 了      。

Truffle 是一个用 Java 写就的语言实现框架                    。基于 Truffle 的语言实现仅需用 Java 实现词法分析                   、语法分析以及针对语法分析所生成的抽象语法树(Abstract Syntax Tree,AST)的解释执行器                   ,便可以享用由 Truffle 提供的各项运行时优化             。

就一个完整的 Truffle 语言实现而言                   ,由于实现本身以及其所依赖的 Truffle 框架部分都是用 Java 实现的,因此它可以运行在任何 Java 虚拟机之上      。

当然             ,如果 Truffle 运行在附带了 Graal 编译器的 Java 虚拟机之上                   ,那么它将调用 Graal 编译器所提供的 API      ,主动触发对 Truffle 语言的即时编译             ,将对 AST 的解释执行转换为执行即时编译后的机器码                   。

目前除了 Java                   , JavaScript             、Ruby、Python 和许多其他流行语言都已经可以运行在 GraalVM 之上了             。

GraalVM 官方还提供了完整的文档      ,当有一天你开发了一款新的语言       ,也可以用 Truffle 让它跑在 GraalVM 上。

安装和使用

GraalVm 目前的最新版本是 22.3                   ,分为社区版和企业版             ,就好像 OpenJDK 和 商用的 Orcale 的 JDK        ,企业版会多一些性能分析的功能                   ,用来帮助更大程度的优化性能                   。

社区版是基于OpenJDK 11.0.17, 17.0.5, 19.0.1             ,而商业版基于Oracle JDK 8u351, 11.0.17, 17.0.5, 19.0.1,所以                   ,如果你想用免费的                   ,只能将程序升级到 JDK 11 以上了                   。

GraalVM 支持 Windows                   、Linux                   、MacOS ,可以用命令安装最新版             ,或者直接下载对应 Java 版本的。

我是下载的 Java 11 的版本                   ,下载下来的压缩包      ,直接解压             ,然后配置环境变量             。把解压目录配置到环境变量的 JAVA_HOME就可以了                   。

解压好其实就相当于安装完毕了                   ,查看一下版本      。

进入到解压目录下的bin目录中      ,运行 java -version             。运行结果如下:

运行代码

常用方式运行

也就是我们平时一直在用的这种方式       ,把 GrralVM 当做 OpenJDK 使用                   ,只不过把即时编译器换成了 Graal                    。就是前面说的第一种方式      。

安装完成后             ,就可以把它当做正常的 JDK 使用了       ,比如 javac、jps             、jmap等都可以直接用了      。大多数人还是用 IDEA 的                   ,所以就直接在 IDEA 中使用就好了                    。

1                   、先随意创建一个 Java 项目             。

2      、创建完成后             ,打开项目设置      。

3             、在打开的项目设置弹出框中选择 SDKs,点击加号                   ,选择前面解压的 GraalVM 目录                   。

4                    、然后选择刚刚添加的这个 JDK             。

5      、最后运行一段测试代码。

public class HelloWorld { public static void main(String[] args) throws Exception { System.out.println("Hello GraalVM!"); Thread.sleep(1000 * 100 * 100); } }

上面这样的运行方式                   ,其实就相当于前面说的第一种运行方式

native-image 方式运行

这种方式就是 AOT 编译成机器码,已可执行文件的形式出现                   。native-image 可以命令行的形式执行             ,也可以在配合 Maven 执行                   ,我这儿就直接演示用 Maven 形式的了      ,毕竟IDEA 搭配 Maven 用习惯了                   。

1      、安装native-image 工具包

native-image 是用来进行 AOT 编译打包的工具             ,先把这个装上                   ,才能进行后面的步骤。

安装好 GraalVM 后      ,在 bin目录下有一个叫做 gu的工具       ,用这个工具安装                   ,如果将 bin目录添加到环境中             ,直接下面的命令安装就行了             。

gu install native-image

如果没有将 bin目录加到环境变量中       ,要进入到 bin目录下                   ,执行下面的命令安装                   。

./gu install native-image

这个过程可能比较慢             ,因为要去 github 上下载东西,如果一次没成功(比如超时)                   ,多试两次就好了      。

2                    、配置 Maven

配置各种版本

<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>${java.specification.version} </maven.compiler.source> <maven.compiler.target>${java.specification.version}</maven.compiler.target> <native.maven.plugin.version>0.9.12</native.maven.plugin.version> <imageName>graalvm-demo-image</imageName> <mainClass>org.graalvm.HelloWorld</mainClass> </properties>

native.maven.plugin.version是要用到的编译为可执行程序的 Maven 插件版本             。

imageName是生成的可执行程序的名称                    。

mainClass是入口类全名称      。

配置 build 插件

<build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <id>java-agent</id> <goals> <goal>exec</goal> </goals> <configuration> <executable>java</executable> <workingDirectory>${project.build.directory}</workingDirectory> <arguments> <argument>-classpath</argument> <classpath/> <argument>${mainClass}</argument> </arguments> </configuration> </execution> <execution> <id>native</id> <goals> <goal>exec</goal> </goals> <configuration> <executable>${project.build.directory}/${imageName}</executable> <workingDirectory>${project.build.directory}</workingDirectory> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>${maven.compiler.source}</source> <target>${maven.compiler.source}</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.2.2</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <mainClass>${mainClass}</mainClass> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <mainClass>${mainClass}</mainClass> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> </plugins> </build>

配置 profiles

<profiles> <profile> <id>native</id> <build> <plugins> <plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> <version>${native.maven.plugin.version}</version> <extensions>true</extensions> <executions> <execution> <id>build-native</id> <goals> <goal>build</goal> </goals> <phase>package</phase> </execution> <execution> <id>test-native</id> <goals> <goal>test</goal> </goals> <phase>test</phase> </execution> </executions> <configuration> <fallback>false</fallback> <buildArgs> <arg>-H:DashboardDump=fortune -H:+DashboardAll</arg> </buildArgs> <agent> <enabled>true</enabled> <options> <option>experimental-class-loader-support</option> </options> </agent> </configuration> </plugin> </plugins> </build> </profile> </profiles>

3             、使用 maven 编译                   ,打包成本地可执行程序      。

执行 Maven 命令

mvn clean package

或者

mvn -Pnative -Dagent package

编译打包的过程比较慢,因为要直接编译成机器码             ,所以比一般的编译过程要慢一些                    。看到下面的输入日志                   ,说明打包成功了             。

4      、运行可执行程序包      ,打开 target 目录             ,已经看到了graalvm-demo-image可执行程序包了                   ,大小为 11.58M      。

然后就可以运行它了      ,进入到目录下       ,执行下面的命令运行                   ,可以看到正常输出了                   。注意了             ,这时候已经是没有用到本地 JVM 了             。

./graalvm-demo-image Hello GraalVM!

这时候       ,用 jps -l命令已经看不到这个进程了                   ,只能通过 ps看了。

总结

虽然我们还没有看到有哪个公司说在用 GraalVM 了             ,但是 Quarkus                   、Spring Boot             、Spring等很多的框架都已经支持 GraalVM 的 Native-image 模式,而且在 Orcale 的大力推广下                   ,相信不久之后就会出现在更多的产品中                   。赶紧体验一下吧                   。

如果觉得还不错的话                   ,给个推荐吧!

公众号「古时的风筝」,Java 开发者             ,专注 Java 及周边生态。坚持原创干货输出                   ,你可选择现在就关注我      ,或者看看历史文章再关注也不迟             。长按二维码关注             ,跟我一起变优秀!

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
linux系统vi编辑器(Linux上vi(vim)编辑器使用教程) 如何提高站内seo效果?站内seo的形式主要包括这些内容(如何提高站内SEO效果?站内SEO的形式主要包括这些!)