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

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

时间2025-07-31 16:15:35分类IT科技浏览5488
导读:大家好,我是风筝,公众号「古时的风筝」,专注于 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
loki雷神官网(Loki (C++) Wikipedia, the free encyclopedia) 特征降维pca(Python特征降维如何理解)