个人什么取消网站备案,一级域名免费网站怎么申请,wordpress搬家至本地及域名替换,苏州seo推广前面松哥写了一篇文章和大家聊了 Spring6 中引入的新玩意 AOT#xff08;见Spring Boot3 新玩法#xff0c;AOT 优化#xff01;#xff09;。
文章发出来之后#xff0c;有小伙伴问松哥有没有做性能比较#xff0c;老实说#xff0c;这个给落下了#xff0c;所以今天…前面松哥写了一篇文章和大家聊了 Spring6 中引入的新玩意 AOT见Spring Boot3 新玩法AOT 优化。
文章发出来之后有小伙伴问松哥有没有做性能比较老实说这个给落下了所以今天再来一篇文章和小伙伴们梳理比较小当我们利用 Native Image 的时候Spring Boot 启动性能从参数上来说到底提升了多少。 先告诉大家结论启动速度提升 10 倍以上。 1. Native Image
1.1 GraalVM
不知道小伙伴们有没有注意到现在当我们新建一个 Spring Boot 工程的时候再添加依赖的时候有一个 GraalVM Native Support这个就是指提供了 GraalVM 的支持。 那么什么是 GraalVM 呢
GraalVM 是一种高性能的通用虚拟机它为 Java 应用提供 AOT 编译和二进制打包能力基于 GraalVM 打出的二进制包可以实现快速启动、具有超高性能、无需预热时间、同时需要非常少的资源消耗所以你把 GraalVM 当作 JVM 来用是没有问题的。
在运行上GraalVM 同时支持 JIT 和 AOT 两种模式 JIT 是即时编译Just-In-Time Compilation的缩写。它是一种在程序运行时将代码动态编译成机器码的技术。与传统的静态编译Ahead-of-Time Compilation不同静态编译是在程序执行之前将代码编译成机器码而 JIT 编译器在程序运行时根据需要将代码片段编译成机器码然后再运行。所以 JIT 的启动会比较慢因为编译需要占用运行时资源。我们平时使用 Oracle 提供的 Hotspot JVM 就属于这种。 AOT 是预先编译Ahead-of-Time Compilation的缩写。它是一种在程序执行之前将代码静态编译成机器码的技术。与即时编译JIT不同即时编译是在程序运行时动态地将代码编译成机器码。AOT 编译器在程序构建或安装阶段将代码转换为机器码然后在运行时直接执行机器码而无需再进行编译过程。这种静态编译的方式可以提高程序的启动速度和执行效率但也会增加构建和安装的时间和复杂性。AOT 编译器通常用于静态语言的编译过程如 C、C 等。
如果我们在 Java 应用程序中使用了 AOT 技术那么我们的 Java 项目就会被直接编译为机器码可以脱离 JVM 运行运行效率也会得到很大的提升。
那么什么又是 Native Image 呢
1.2 Native Image
Native Image 则是 GraalVM 提供的一个非常具有特色的打包技术这种打包方式可以将应用程序打包为一个可脱离 JVM 在本地操作系统上独立运行的二进制包这样就省去了 JVM 加载和字节码运行期预热的时间提升了程序的运行效率。
Native Image 具备以下特点
即时启动由于不需要 JVM 启动和类加载过程Native Image 可以实现快速启动和即时执行。减少内存占用编译成本地代码后应用程序通常会有更低的运行时内存占用因为它们不需要 JVM 的额外内存开销。静态分析在构建 Native Image 时GraalVM 使用静态分析来确定应用程序的哪些部分是必需的并且只包含这些部分这有助于减小最终可执行文件的大小。即时性能虽然 JVM 可以通过JITJust-In-Time编译在运行时优化代码但 Native Image 提供了即时的、预先优化的性能这对于需要快速响应的应用程序特别有用。跨平台兼容性Native Image 可以为不同的操作系统构建特定的可执行文件包括 Linux、macOS 和 Windows即在 Mac 和 Linux 上自动生成系统可以执行的二进制文件在 Windows 上则自动生成 exe 文件。安全性由于 Native Image 不依赖于 JVM因此减少了 JVM 可能存在的安全漏洞的攻击面。与 C 语言互操作Native Image 可以与本地 C 语言库更容易地集成因为它们都是在同一环境中运行的本地代码。
根据前面的介绍大家也能看到GraalVM 所做的事情就是在程序运行之前该编译的就编译好这样当程序跑起来的时候运行效率就会高而这一切就是利用 AOT 来实现的。
但是对于一些涉及到动态访问的东西GraalVM 似乎就有点力不从心了原因很简单GraalVM 在编译构建期间会以 main 函数为入口对我们的代码进行静态分析静态分析的时候一些无法触达的代码会被移除而一些动态调用行为例如反射、动态代理、动态属性、序列化、类延迟加载等这些都需要程序真正跑起来才知道结果这些就无法在编译构建期间被识别出来。
而反射、动态代理、序列化等恰恰是我们 Java 日常开发中最最重要的东西不可能我们为了 Native Image 舍弃这些东西因此从 Spring6Spring Boot3开始支持 AOT ProcessingAOT Processing 用来完成自动化的 Metadata 采集这个采集主要就是解决反射、动态代理、动态属性、条件注解动态计算等问题在编译构建期间自动采集相关的元数据信息并生成配置文件然后将 Metadata 提供给 AOT 编译器使用。
道理搞明白之后接下来通过一个案例来感受下 Native Image 的威力吧
2. 准备工作
首先需要我们安装 GraalVM。
GraalVM 下载地址
https://www.graalvm.org/downloads/
下载下来之后就是一个压缩文件解压然后配置一下环境变量就可以了这个默认大家都会我就不多说了。
GraalVM 配置好之后还需要安装 Native Image 工具命令如下
gu install native-image装好之后可以通过如下命令检查安装结果
另一方面Native Image 在进行打包的时候会用到一些 C/C 相关的工具所以还需要在电脑上安装 Visual Studio 2022这个我们安装社区版就行了https://visualstudio.microsoft.com/zh-hans/downloads/ 下载后双击安装就行了安装的时候选择 C 桌面应用开发。 如此之后准备工作就算完成了。
3. 实践
接下来我们创建一个 Spring Boot 工程并且引入如下两个依赖 然后我们开发一个接口
RestController
public class HelloController {AutowiredHelloService helloService;GetMapping(/hello)public String hello() {return helloService.sayHello();}
}
Service
public class HelloService {public String sayHello() {return hello aot;}
}这是一个很简单的接口接下来我们分别打包成传统的 jar 和 Native Image。
传统 jar 包就不用我多说了大家执行 mvn package 即可
mvn package打包完成之后我们看下耗时时间 耗时不算很久差不多 3.7s 左右算是比较快了最终打成的 jar 包大小是 18.9MB。
再来看打成原生包执行如下命令
mvn clean native:compile -Pnative这个打包时间就比较久了需要耐心等待一会 可以看到总共耗时 4 分 54 秒。
Native Image 打包的时候如果我们是在 Windows 上会自动打包成 exe 文件如果是 Mac/Linux则生成对应系统的可执行文件。 这里生成的 aot_demo.exe 文件大小是 82MB。
两种不同的打包方式所耗费的时间完全不在一个量级。
再来看启动时间。
先看 jar 包启动时间 耗时约 1.326s。
再来看 exe 文件的启动时间 好家伙只有 0.079s。
1.326/0.07916.78
启动效率提升了 16.78 倍
我画个表格对比一下这两种打包方式
jarNative Image包大小18.9MB82MB编译时间3.7s4分54s启动时间1.326s0.079s
从这张表格中我们可以看到Native Image 在打包的时候比较费时间但是一旦打包成功项目运行效率是非常高的。Native Image 很好的解决了 Java 冷启动耗时长、Java 应用需要预热等问题。
最后大家可以自行查看打包成 Native Image 时候的编译结果如下图 看过松哥之前将的 Spring 源码分析的小伙伴这块的代码应该都很好明白这就是直接把 BeanDefinition 给解析出来了不仅注册了当前 Bean也把当前 Bean 所需要的依赖给注入了将来 Spring 执行的时候就不用再去解析 BeanDefinition 了。
同时我们可以看到在 META-INF 中生成了 reflect、resource 等配置文件。这些是我们添加的 native-maven-plugin 插件所分析出来的反射以及资源等信息也是 Spring AOT Processing 这个环节处理的结果。