- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
大家好,我是风筝,公众号「古时的风筝」,专注于 Java技术 及周边生态。 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面.
今天说一说 GraalVM.
GraalVM 是 Oracle 大力发展和想要推广的新一代 JVM ,目前很多框架都已经渐渐支持 GraalVM 了,比如我们在用的 Spring 也已经推出了对 GraalVM 兼容的工具包了.
既然说的这么厉害,那么它到底是何方神圣呢.
既然叫做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 上,不存在跨语言调用的壁垒.
Java 虚拟机都是内置在 JDK 中的,比如Orcale JDK、OpenJDK,默认内置的都是 HotSpot 虚拟机.
GraalVM 也是一种 JDK,一种高性能的 JDK。完全可以用它替代 OpenJDK、Orcale JDK.
说了半天,是不是还是不知道 GraalVM 到底是什么.
GraalVM - 还包含 Graal (JIT)即时编译器,可以结合 HotSpot 使用 。
GraalVM – 是一种高性能 JDK,旨在加速 Java 应用程序性能,同时消耗更少的资源.
GraalVM - 是一种支持多语言混编的虚拟机程序,不仅可以运行 JVM 系列的语言,也可支持其他语言.
GraalVM 提供了两种方式来运行 Java 程序.
上面说了,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 的一切都用不了.
这是 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 中的另一个核心组件 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);
}
}
上面这样的运行方式,其实就相当于前面说的第一种运行方式 。
这种方式就是 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 及周边生态。坚持原创干货输出,你可选择现在就关注我,或者看看历史文章再关注也不迟。长按二维码关注,跟我一起变优秀! 。
最后此篇关于过两年JVM可能就要被GraalVM替代了的文章就讲到这里了,如果你想了解更多关于过两年JVM可能就要被GraalVM替代了的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
这很可能是我的语法错误,因为我对在 C++ 中使用多个文件和结构(特别是将结构传递给函数)还很陌生。这是三个文件: 主要.cpp: #include #include #include #inc
我有 TypeScript NestJS 项目。 我需要验证传入的 DTO 到我的 API。它可以被描述为“创建项目”,其中我们有建筑类型(房屋、公寓、花园),并根据该类型我们需要定义: 房屋:楼层包
是否可以从可用于泛型参数的可能类型集中排除特定类型?如果是如何。 例如 Foo() : where T != bool 将意味着除了类型 bool 之外的任何类型。 编辑 为什么? 以下代码是我尝试强
我的 WebGL 体积光线转换应用程序即将完成。但是我发现了一个问题。我必须通过 2D 纹理模拟 3D 纹理。这不是问题。我正在用小切片创建一个巨大的纹理。巨大纹理的尺寸约为 4096x4096 像素
我正在处理的网页上显示了一个返回顶部按钮。当您向下滚动时,有时单击它时,它会跳到顶部,然后跳回您在页面上的位置,然后像预期的那样平滑滚动到顶部。请记住,它并不总是这样做。这只是一个滞后或故障问题还是我
我对此还很陌生,所以请耐心等待。 我有一个类,它具有三个属性:几个整数和一个用户定义对象的集合。 public class Response { public int num1 { get;
我正在制作一款平台游戏,让玩家每 30 毫秒跳跃一次,并向上添加少量的力。我想我应该使用多线程,因为我之前已经做过一些,而且看起来很简单。无论如何,我尝试了这个: public void jump()
是否可以从可能的类型集中排除特定类型,这些类型可以在泛型参数中使用?如果是这样的话。 例如 Foo() : where T != bool 表示除 bool 类型之外的任何类型。 编辑 为什么? 以下
我正在尝试在单个查询中实现内部和外部联接,我不确定我的做法是正确还是错误,因为我不太擅长查询。 就这样吧。 我有以下表格。 hrs_residentials hrs_residential_utili
关于 my website ,有一段代码可以向页面添加几个元素。这段代码不是我可以编辑的东西,而且我对它放置这些元素的位置不满意,因为它弄乱了我的一些布局。所以我想出了一个小的 jQuery 来将它们
一位客户希望我创建一个数据集,如下所示。我不知道这是否可能或合乎逻辑。 我有表parent: id name ------- ------- 1 parent1 2
这可能吗?google 好像没有这方面的资料.. 这样,如果用户在另一个网站上播放视频或歌曲,我的音量就会自动减小 最佳答案 不,这是不可能的。 如果可能的话,它必须是特定于浏览器的,但我不认为这种情
所以我正在尝试制作响应式页面。问题是为什么它归结为移动数据需要位于列表中。 我会用一些示例代码来解释 所以这可能是桌面上的输出 option1
当您将鼠标悬停在a 元素 上时,是否可以删除url? 这就是我的意思: 最佳答案 一种选择是使用一些 JavaScript。 删除 href=来自 的属性标签,取而代之的是 onclick=...
我已经考虑了几个小时,但我无法取得太大进展。它是这样的: You have an array of size n and q queries. Each query is of the form (l
我一直在尝试编写一个脚本来强化 android。我没有成功! 我正在通过模拟器运行一个 AVD,并且已经用我加载的 android shell 和 bash shell 试过了。正如您将在下面看到的那
Private Sub Workbook_Open() Dim WBname As String WBname = ThisWorkbook.name If Not InStr(WBname, "te
Spark 2.0.0-预览版 我们有一个应用程序使用了相当大的广播变量。我们在大型 EC2 实例上运行它,因此部署处于客户端模式。广播变量是一个巨大的 Map[String, Array[Strin
我正在尝试从此link中提取摘要。但是,我无法仅提取摘要的内容。到目前为止,这是我完成的工作: url <- "http://www.scielo.br/scielo.php?script=sci_a
我的主页中有一个iframe。 iframe页面中有一个modalpopup。因此,当显示modalpopup时,modalpopup的父级是iframe主体和主页父级主体。因此,覆盖层仅覆盖ifra
我是一名优秀的程序员,十分优秀!