全功能電子商務(wù)網(wǎng)站建設(shè)百度推廣關(guān)鍵詞怎么優(yōu)化
有道無術(shù),術(shù)尚可求,有術(shù)無道,止于術(shù)。
本系列Spring Boot版本2.7.0
文章目錄
- 概述
- JIT & AOT
- JIT (動(dòng)態(tài)編譯)
- AOT(靜態(tài)編譯)
- GraalVM
- 簡介
- 運(yùn)行模式
- Native Image(原生鏡像)
- Spring Native
- 案例演示
- 1. 安裝 GraalVM Native-image C++環(huán)境
- 2. 項(xiàng)目測試
概述
本篇介紹如何使用GraalVM
構(gòu)建原生鏡像。
在開發(fā)Spring Boot
應(yīng)用或者其他JAVA
程序的過程中,啟動(dòng)慢、內(nèi)存占用大是比較頭疼的問題,往往需要更多的資源去部署,成本大幅提高。為了優(yōu)化上述問題,常常使用優(yōu)化程序、使用更小消耗的JVM、使用容器等措施。
現(xiàn)在有一個(gè)叫做Native Image
(原生鏡像)的技術(shù),可以將JAVA
應(yīng)用的字節(jié)碼直接編譯為本地機(jī)器碼,打包成本地可執(zhí)行文件,運(yùn)行應(yīng)用時(shí)無需Java
虛擬機(jī)進(jìn)行動(dòng)態(tài)編譯,因此啟動(dòng)速度很快、內(nèi)存消耗也很低。
JIT & AOT
在正式介紹Native Image
之前,我們需要了解下JIT
和 AOT
的相關(guān)概念。
通常程序有兩種運(yùn)行方式:
- 動(dòng)態(tài)解釋:解釋執(zhí)行,運(yùn)行時(shí)翻譯為機(jī)器碼。
- 靜態(tài)編譯:程序在執(zhí)行前全部被翻譯為機(jī)器碼,可以直接運(yùn)行二進(jìn)制文件。
JIT (動(dòng)態(tài)編譯)
JIT
是Just-in-time
的縮寫,一般稱為即時(shí)編譯或動(dòng)態(tài)編譯。Java
源代碼在運(yùn)行的過程中,類加載器將需要運(yùn)行的字節(jié)碼處理并分配到內(nèi)存中,然后JVM
執(zhí)行引擎需要調(diào)用解釋器將字節(jié)碼翻譯為計(jì)算機(jī)能執(zhí)行的機(jī)器碼,最后執(zhí)行機(jī)器指令。
需要解釋執(zhí)行勢必會(huì)造成運(yùn)行效率降低,為了提高執(zhí)行速度,JAVA
引入了 JIT
編譯器。當(dāng)某個(gè)方法或代碼塊運(yùn)行特別頻繁的時(shí)候,JVM
會(huì)將其標(biāo)注為熱點(diǎn)代碼, JIT
編譯器會(huì)將熱點(diǎn)代碼編譯成本地機(jī)器相關(guān)的機(jī)器碼,優(yōu)化后進(jìn)行緩存,下次執(zhí)行這些代碼時(shí),直接調(diào)用緩存中的機(jī)器碼,無需重復(fù)解釋,在一定程度上提高了執(zhí)行速度。
AOT(靜態(tài)編譯)
JAVA
一直在努力提高啟動(dòng)和運(yùn)行時(shí)性能,希望其能夠在更廣泛的場景達(dá)到或接近本地語言的性能。雖然引入了JIT
編譯器,但是需要花費(fèi)較長時(shí)間才能熱身完,而且有些Java
方法還沒法編譯,性能方面也會(huì)下降。
AOT
是Ahead-of-Time
的縮寫,一般稱為靜態(tài)編譯。程序在執(zhí)行前全部被翻譯為機(jī)器碼,可以直接運(yùn)行二進(jìn)制文件,比如C++
就是使用靜態(tài)編譯。
在 JDK 9
中, AOT
作為實(shí)驗(yàn)特性被引入,只支持 java.base
模塊可以編譯成AOT
庫,使用jaotc
工具將Java
類文件編譯為本機(jī)代碼,避免了 JIT
預(yù)熱等各方面的開銷。但是實(shí)際運(yùn)行效果不盡人意,最終在JDK 16
中被刪除。
在JDK 17
中,也移除了實(shí)驗(yàn)性的AOT
與JIT
,徹底擁抱GraalVM
實(shí)現(xiàn)靜態(tài)編譯。
在當(dāng)前微服務(wù)、云原生盛行的時(shí)代,JAVA 程序
顯得越來越臃腫,雖然使用AOT
也有諸多缺點(diǎn),比如打包時(shí)間長、舍棄平臺無關(guān)性、反射、JNI、動(dòng)態(tài)代理的分析能力有限。但是JAVA
必定會(huì)向AOT
發(fā)展,否則在云原生時(shí)代,可以能被其他后起之秀慢慢蠶食市場。
GraalVM
簡介
官網(wǎng)地址
GitHub地址
GraalVM
是一個(gè)高性能跨語言虛擬機(jī),其目的是提升Java
和其他JVM
語言編寫程序的執(zhí)行速度,同時(shí)也為JavaScript
、Python
和許多其他流行語言提供運(yùn)行時(shí)環(huán)境。起始于 2011 年 Oracle
實(shí)驗(yàn)室的一個(gè)研究項(xiàng)目。
GraalVM
三大核心:
- 為
Java
虛擬機(jī)提供高性能的JIT
編譯器 - 高性能的
AOT
編譯器,提前將Java
字節(jié)碼編譯為本機(jī)機(jī)器碼。 - 多種語言的支持,
GraalVM
的Truffle
語言實(shí)施框架可與GraalVM
編譯器協(xié)作,以卓越性能運(yùn)行JavaScript、Python、Ruby
以及JVM
支持的其他語言。
GraalVM
提供了兩種運(yùn)行Java
應(yīng)用程序的方法:
- 在
HotSpot JVM
上使用實(shí)時(shí)JIT
編譯器 - 使用
AOT
將Java
應(yīng)用程序編譯的本地可執(zhí)行文件
社區(qū)版和企業(yè)版的一些區(qū)別:
- 社區(qū)版基于
Open JDK
,由社區(qū)組織維護(hù) - 社區(qū)版無定制的高級編譯器優(yōu)化
- 在原生鏡像中,社區(qū)版無壓縮指針、配置文件引導(dǎo)優(yōu)化、G1垃圾收集
GraalVM
的優(yōu)點(diǎn):
-
幫助開發(fā)人員顯著提升應(yīng)用的性能效率,同時(shí)降低
IT
成本。 -
構(gòu)建現(xiàn)代
Java
應(yīng)用,通過微服務(wù)和容器來滿足云原生需求,微服務(wù)是執(zhí)行單一功能的小型、獨(dú)立微應(yīng)用。在現(xiàn)實(shí)中,業(yè)務(wù)應(yīng)用通常要使用數(shù)百項(xiàng)服務(wù),每項(xiàng)服務(wù)都需要快速啟動(dòng),以盡可能降低延遲和云使用成本。 -
可以構(gòu)建一個(gè)各種編程語言基于單一
JVM
運(yùn)行的生態(tài)系統(tǒng),提高開發(fā)效率。
GraalVM
的缺點(diǎn):
- 舍棄了
Java
的平臺無關(guān)性,編譯為本地執(zhí)行文件,不同操作系統(tǒng)的服務(wù)器,編譯出來的文件不一樣,比如Windows
編譯出來的文件,并不能在Linux
系統(tǒng)運(yùn)行,也就讓JAVA
丟失了平臺無關(guān)性。JAVA
設(shè)計(jì)之初,一次編譯、到處運(yùn)行是其最重要的特性,但是現(xiàn)在容器技術(shù)的出現(xiàn),該特性顯得很牽強(qiáng)。 - 反射機(jī)制、
CGLIB
動(dòng)態(tài)代理這些和字節(jié)碼打交道的機(jī)制,是在程序運(yùn)行時(shí)動(dòng)態(tài)調(diào)用,無法經(jīng)過AOT
編譯成原生代碼,構(gòu)建時(shí)還需要提供各種配置文件去適配。 - 目前該技術(shù)并未大面積使用,并不成熟。
運(yùn)行模式
GraalVM
提供了多種操作模式。
1、JVM運(yùn)行時(shí)模式
在HotSpot JVM
上運(yùn)行程序時(shí),默認(rèn)使用GraalVM
編譯器作為頂級JIT
編譯器。在運(yùn)行時(shí),應(yīng)用程序在JVM上
正常加載和執(zhí)行。JVM
將字節(jié)碼傳遞給編譯器,編譯器將其編譯為機(jī)器代碼并將其返回給JVM
。
2、原生鏡像
Native Image
是一種創(chuàng)新技術(shù),它將Java
代碼編譯為獨(dú)立的本地可執(zhí)行文件或本地共享庫。在構(gòu)建本機(jī)可執(zhí)行文件期間,處理的Java
字節(jié)碼包括所有應(yīng)用程序類、依賴項(xiàng)、依賴于第三方的庫以及所需的任何JDK類。生成的本地可執(zhí)行文件特定于每個(gè)操作系統(tǒng)和機(jī)器體系結(jié)構(gòu),并不需要JVM
。
從當(dāng)前GraalVM 22.1
支持的功能圖可以看出,Native Image
可以在AMD6
、AArch64
等服務(wù)器平臺生成環(huán)境使用。
3、Java on Truffle
Java on Truffle
是一個(gè) JVM
實(shí)現(xiàn),它使用了 Truffle
多語言執(zhí)行框架。提供了Java
虛擬機(jī)所有的核心組件,實(shí)現(xiàn)了與Java
運(yùn)行時(shí)環(huán)境庫相同的API
,并重用GraalVM中
的所有JAR
和本機(jī)庫。支持多語言互操作,例如,JavaScript
程序可以運(yùn)行Ruby
方法,無需制作副本就能共享數(shù)值?;?code>JVM運(yùn)行時(shí),Truffle
能夠與GraalVM
編譯器協(xié)作,將受支持語言編譯為本機(jī)機(jī)器碼,從而優(yōu)化性能。
Native Image(原生鏡像)
了解了GraalVM
之后,我們著重了解并使用Native Image
技術(shù)將一個(gè)Spring Boot 3
項(xiàng)目編譯為一個(gè)可執(zhí)行二進(jìn)制文件。
Native Image
:是一種將Java
代碼提前編譯為二進(jìn)制文件的技術(shù),即本機(jī)可執(zhí)行文件。本機(jī)可執(zhí)行文件只包含運(yùn)行時(shí)所需的代碼,即應(yīng)用程序類、標(biāo)準(zhǔn)庫類、語言運(yùn)行時(shí)以及來自JDK的靜態(tài)鏈接本機(jī)代碼。
Native Image
處理應(yīng)用程序類和其他元數(shù)據(jù),以創(chuàng)建特定操作系統(tǒng)和體系結(jié)構(gòu)的二進(jìn)制文件。首先,本地鏡像工具對代碼執(zhí)行靜態(tài)分析,以確定應(yīng)用程序運(yùn)行時(shí)可訪問的類和方法。其次,它將類、方法和資源編譯成二進(jìn)制文件。整個(gè)過程被稱為構(gòu)建,以明確區(qū)分它與Java
源代碼到字節(jié)碼的編譯。
Native Image
生成的可執(zhí)行文件優(yōu)點(diǎn):
- 使用虛擬機(jī)所需資源的一小部分,運(yùn)行時(shí)更低的內(nèi)存消耗
- 以毫秒為單位啟動(dòng)
- 立即提供最高性能,無需預(yù)熱
- 可以打包成輕量級容器映像,以實(shí)現(xiàn)快速高效的部署
- 更不容易遭到破解、攻擊
Spring Native
Spring Native
是Spring
社區(qū)的一個(gè)開源框架,可以通過GraalVM
將Spring
應(yīng)用程序編譯成原生鏡像。
但是在GitHub
可以看到,該項(xiàng)目已經(jīng)關(guān)閉了:
官方推薦使用Spring Boot 3
+GraalVM
官方構(gòu)建工具實(shí)現(xiàn)原生鏡像構(gòu)建,所以要注意Spring Native
已經(jīng)沒必要再去研究及使用了
案例演示
官方環(huán)境要求文檔
首先需要安裝GraalVM
、native-image
組件,C++
環(huán)境,最好不要在Windows
上使用,可以看到Spring Boot
官網(wǎng)給出Windows
上使用的注意事項(xiàng),就算按步驟做了~ 也有可能各種報(bào)錯(cuò),所以切勿嘗試😁😁😁
1. 安裝 GraalVM Native-image C++環(huán)境
下載地址
選擇系統(tǒng)對應(yīng)的GraalVM
、Native-image
安裝包并下載,這里我使用的是Linux Ubuntu
系統(tǒng)。
將文件上傳到Linux
服務(wù)器:
執(zhí)行以下命令安裝GraalVM
# 解壓tar -zxvf graalvm-ce-java17-linux-amd64-22.3.1.tar.gz
# 添加環(huán)境變量
vim /etc/profile
# 添加內(nèi)容
JAVA_HOME=/root/graalvm-ce-java17-22.3.1/
CLASSPATH=$JAVA_HOME/lib/
PATH=$PATH:$JAVA_HOME/bin
export PATH JAVA_HOME CLASSPATH
# 環(huán)境變量生效
source /etc/profile
# 查看
java -version
執(zhí)行以下命令安裝native-image
# 安裝
gu -L install native-image-installable-svm-java17-linux-amd64-22.3.1.jar
# 查看
gu list
執(zhí)行以下命令安裝C++
環(huán)境:
# Ubuntu 系統(tǒng)
sudo apt-get install build-essential libz-dev zlib1g-dev
2. 項(xiàng)目測試
準(zhǔn)備一個(gè)Spring Boot 3.0.3
項(xiàng)目:
添加GraalVM
官方提供的構(gòu)建插件:
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><!--原生鏡像構(gòu)建插件--><plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId><version>0.9.20</version><extensions>true</extensions><executions><execution><id>build-native</id><goals><goal>compile-no-fork</goal></goals><phase>package</phase></execution><execution><id>test-native</id><goals><goal>test</goal></goals><phase>test</phase></execution></executions><configuration><mainClass>com.pearl.nativeimagedemo.NativeImageDemoApplication</mainClass><imageName>native-image-demo</imageName><buildArgs><buildArg>--verbose</buildArg></buildArgs></configuration></plugin></plugins></build>
在Linux
服務(wù)器上安裝Maven
,將項(xiàng)目代碼上傳到服務(wù)器(內(nèi)存至少6G,太少會(huì)卡住),執(zhí)行mvn -Pnative -DskipTests native:compile
編譯,時(shí)間還是蠻久的,雖然這個(gè)項(xiàng)目比較空。
編譯后在target
下生成可執(zhí)行文件,直接使用./native-image-demo
就可運(yùn)行,可以看到啟動(dòng)時(shí)間只有幾十毫秒: