中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

過兩(liang)年(nian) JVM 可能就要被 GraalVM 替代了

大家好,我是風箏,公眾號「古時的風箏」,專注于 Java技術 及周邊生態。
文章會收錄在 中,更有 Java 后端知識圖譜,從小白到大牛要走的路都在里面。

今天說(shuo)一(yi)說(shuo) GraalVM。

GraalVM 是(shi) Oracle 大力(li)發展和想要推廣(guang)的新一代 JVM ,目前很多框架都已(yi)經漸(jian)漸(jian)支持 GraalVM 了,比如我們在用的 Spring 也已(yi)經推出了對(dui) GraalVM 兼(jian)容的工(gong)具包了。

既然說的這么厲害,那么它(ta)到底是何方神圣(sheng)呢。

GraalVM 和 JVM 的關系

既然叫做(zuo)VM,那肯定和 JVM 有關系的(de)吧。JVM 全稱 Java 虛(xu)擬(ni)(ni)機(ji),我們(men)都知道,Java 程序(xu)是運行在虛(xu)擬(ni)(ni)機(ji)上的(de),虛(xu)擬(ni)(ni)機(ji)提供(gong) Java 運行時,支持解釋執行和部分(fen)的(de)(JIT)即時編譯器(qi),并(bing)且負責分(fen)配和管理(li) Java 運行所需(xu)的(de)內存,我們(men)所說(shuo)的(de)各種垃圾收集器(qi)都工作在 JVM 中(zhong)。

比如(ru) Oracle JDK、OpenJDK ,默認(ren)的(de) JVM 是 HotSpot 虛(xu)(xu)擬(ni)機(ji),這(zhe)是當(dang)前應(ying)用最廣泛的(de)一個虛(xu)(xu)擬(ni)機(ji)。我們(men)平時(shi)見到的(de)各種(zhong)將虛(xu)(xu)擬(ni)機(ji)的(de)書籍、文章、面試題(ti),基本上都是說的(de) HotSpot 虛(xu)(xu)擬(ni)機(ji)。

除(chu)此之外(wai),還有一些商用(yong),或者說小眾的(de)(de)虛擬(ni)機存(cun)在,比如IBM 的(de)(de)J9 JVM,商用(yong)的(de)(de) Zing VM 等。

那 GraalVM 是另一種 Java 虛(xu)擬機嗎?

是,又不全是。

GraalVM 可(ke)以(yi)完全取代(dai)(dai)上面提到的(de)(de)(de)那幾種虛擬機,比如 HotSpot。把你(ni)之前運行(xing)在 HotSpot 上的(de)(de)(de)代(dai)(dai)碼直接(jie)平(ping)移到 GraalVM 上,不(bu)用做任何(he)的(de)(de)(de)改變,甚至(zhi)都感知不(bu)到,項目可(ke)以(yi)完美的(de)(de)(de)運行(xing)。

但是 GraalVM 還有更廣泛的用途,不(bu)僅支持 Java 語言(yan),還支持其(qi)他語言(yan)。這些(xie)其(qi)他語言(yan)不(bu)僅包括(kuo)嫡(di)系(xi)的 JVM 系(xi)語言(yan),例(li)如 Kotlin、Scala,還包括(kuo)例(li)如 JavaScript、Nodejs、Ruby、Python 等。

GraalVM 的(de)野心不(bu)止于此,看上面(mian)的(de)圖,它(ta)的(de)目(mu)的(de)是搭建一個 Framework,最終(zhong)的(de)目(mu)標是想要支持(chi)任何一種語言,無論(lun)哪種語言,可以共同跑在 GraalVM 上,不(bu)存(cun)在跨語言調用的(de)壁壘(lei)。

GraalVM 和JDK有什么關系

Java 虛擬(ni)機都是內置(zhi)在 JDK 中的(de),比如Orcale JDK、OpenJDK,默認內置(zhi)的(de)都是 HotSpot 虛擬(ni)機。

GraalVM 也是(shi)一種(zhong) JDK,一種(zhong)高性能(neng)的 JDK。完全可以用它替代 OpenJDK、Orcale JDK。

GraalVM 如何運行 Java 程序

說了半天,是不是還是不知道 GraalVM 到底是什么。

  • GraalVM - 還包含 Graal (JIT)即時(shi)編譯(yi)器,可以結合 HotSpot 使用

  • GraalVM – 是一種高性(xing)能(neng) JDK,旨在加速 Java 應用程(cheng)序性(xing)能(neng),同(tong)時消耗更(geng)少的資源。

  • GraalVM - 是一種(zhong)支持多(duo)語(yu)言混編的虛擬(ni)機程序(xu),不(bu)僅可以運行 JVM 系(xi)列的語(yu)言,也可支持其他語(yu)言。

GraalVM 提供了兩種方式來運行 Java 程序(xu)。

第一種:結合 HotSpot 使用

上面說了(le),GraalVM 包(bao)含 Graal (JIT)即(ji)時(shi)(shi)編譯器(qi),自從 JDK 9u 版(ban)本之(zhi)后,Orcale JDK 和 OpenJDK 就集成了(le) Graal 即(ji)時(shi)(shi)編譯器(qi)。我(wo)們知道 Java 既有解釋(shi)運行也(ye)有即(ji)時(shi)(shi)編譯。

當程序運行時(shi),解釋器首先(xian)發揮作(zuo)用(yong),代碼(ma)(ma)可以(yi)直(zhi)接執行。隨著時(shi)間推移(yi),即時(shi)編譯(yi)器逐漸(jian)發揮作(zuo)用(yong),把越來越多的(de)代碼(ma)(ma)編譯(yi)優化成(cheng)本(ben)地代碼(ma)(ma),來獲(huo)取更高的(de)執行效率(lv)。即時(shi)編譯(yi)器可以(yi)選擇(ze)性地編譯(yi)熱點代碼(ma)(ma),省(sheng)去了很(hen)多編譯(yi)時(shi)間,也節(jie)省(sheng)很(hen)多的(de)空間。比如多次執行的(de)方法或者(zhe)循環、遞(di)歸等(deng)。

JDK 默(mo)認使用(yong)的是 C2 即時(shi)編(bian)(bian)譯器,C2是用(yong)C++編(bian)(bian)寫的。而(er)使用(yong)下面的參數可以用(yong) Graal 替換 C2。

-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler

Graal 編(bian)譯器(qi)(qi)是(shi)用 Java 實現的(de)(de),用 Java 實現自己(ji)的(de)(de)編(bian)譯器(qi)(qi)。Graal 基(ji)于一(yi)些假設的(de)(de)條(tiao)件,采(cai)取更加激進(jin)的(de)(de)方式進(jin)行優化。采(cai)用 Graal 編(bian)譯器(qi)(qi)之(zhi)后,對性能有會(hui)有一(yi)定的(de)(de)提升。

但是(shi)如果(guo)你還(huan)是(shi)在用(yong) JDK8,那對不起了(le),GraalVM 的一切都用(yong)不了(le)。

第二種:AOT 編譯本地可執行程序

這是 GraalVM 真正厲害的地方。

AOT 提前編譯(yi)(yi)(yi)(yi),是(shi)相對于即(ji)時編譯(yi)(yi)(yi)(yi)而(er)(er)言(yan)的(de)。AOT在運(yun)行過程中耗費 CPU 資源來進行即(ji)時編譯(yi)(yi)(yi)(yi),而(er)(er)程序也能夠(gou)在啟動的(de)瞬間就達到理想的(de)性能。例(li)如 C 和 C++語(yu)言(yan)采用(yong)的(de)是(shi)AOT靜態編譯(yi)(yi)(yi)(yi),直(zhi)接將代碼轉換成機器碼執行。而(er)(er) Java 一直(zhi)采用(yong)的(de)是(shi)解釋 + 即(ji)時編譯(yi)(yi)(yi)(yi)技術(shu),大(da)多數情況(kuang)下(xia) Java 即(ji)時編譯(yi)(yi)(yi)(yi)的(de)性能并不比靜態編譯(yi)(yi)(yi)(yi)差,但是(shi)還(huan)是(shi)一直(zhi)朝著(zhu) AOT 編譯(yi)(yi)(yi)(yi)的(de)方向努(nu)力(li)。

但(dan)是(shi) Java 對于 AOT 來說有一些難點,比(bi)如(ru)類的(de)動(dong)態(tai)加(jia)載和反射調用。

GraalVM 顯然(ran)是已經克服了這些問題,使(shi)用 GraalVM 可(ke)以(yi)直(zhi)接將 Java 代碼編譯成(cheng)本地機器碼形態的可(ke)執(zhi)行(xing)程序(xu)。

我(wo)們目前運(yun)行(xing) Java 一定要(yao)安裝(zhuang) JDK 或(huo)者 JRE 對不對,如果將程(cheng)序直接編(bian)譯(yi)成(cheng)可執行(xing)程(cheng)序,就不用在(zai)服務(wu)器上安裝(zhuang) JDK 或(huo) JRE 了。那就是說運(yun)行(xing) Java 代碼(ma)其實也(ye)可以不用虛擬機了是嗎?

GraalVM 的 AOT 編譯(yi)實(shi)際上是借助了 SubstrateVM 編譯(yi)框架,可以將 SubstrateVM 理(li)(li)解為一個(ge)內嵌精簡版(ban)的 JVM,包(bao)含異常(chang)處理(li)(li),同步(bu),線程管理(li)(li),內存管理(li)(li)(垃圾回收(shou))和 JNI 等組件。

SubstrateVM 的啟動時(shi)間非常短(duan),內(nei)存開(kai)銷非常少。用這種方式編譯出的 Java 程序的執行時(shi)間可與C語言持平。

下(xia)圖是使(shi)(shi)用即時編譯(yi)(JVM運行)與 AOT (原生可(ke)執(zhi)行程序)兩種方式(shi)的 CPU 和(he)內(nei)存(cun)使(shi)(shi)用情況對比,可(ke)以看(kan)出來,AOT 方式(shi)下(xia) CPU 和(he)內(nei)存(cun)的使(shi)(shi)用都非常少。

除了(le)運(yun)行(xing)時(shi)占(zhan)用(yong)的(de)(de)(de)內存少(shao)之外,用(yong)這種方式(shi)最(zui)終生成的(de)(de)(de)可執行(xing)文件也非常小。這對于云端部(bu)署非常友(you)好。目前(qian)很(hen)多場景下都使用(yong) Docker 容(rong)器的(de)(de)(de)方式(shi)部(bu)署,打一(yi)個 Java 程序(xu)的(de)(de)(de)鏡(jing)像(xiang)包要包含完(wan)整的(de)(de)(de) JVM 環境和編譯(yi)好的(de)(de)(de) Jar 包。而(er)AOT 方式(shi)可以(yi)最(zui)大限(xian)度的(de)(de)(de)縮(suo)小 Docker 鏡(jing)像(xiang)的(de)(de)(de)體積。

缺點

好(hao)處多(duo)多(duo),當(dang)然也有一些弊端(duan)。對于反射這(zhe)種純(chun)粹在運行(xing)時才能(neng)確定的(de)部分,不可能(neng)完(wan)全(quan)通(tong)過優化(hua)編譯器解決(jue),只能(neng)通(tong)過增加配(pei)置的(de)方式解決(jue)。麻(ma)煩是麻(ma)煩了一點,但(dan)是是可行(xing)的(de),Spring Boot 2.7的(de)版本已經支持(chi)原生鏡像了,Spring 這(zhe)種非常依賴反射的(de)框架都(dou)可以支撐,我們用起來(lai)也應該(gai)沒問(wen)題。

GraalVM 如何支持多語言

要(yao)支(zhi)持多(duo)語言,就(jiu)要(yao)說(shuo)到 GraalVM 中的另一(yi)個核心組(zu)件(jian) Truffle 了。

Truffle 是一個用(yong)(yong) Java 寫就的(de)語言(yan)實(shi)現框架。基于(yu) Truffle 的(de)語言(yan)實(shi)現僅需用(yong)(yong) Java 實(shi)現詞(ci)法分(fen)(fen)析(xi)、語法分(fen)(fen)析(xi)以及針對語法分(fen)(fen)析(xi)所生成(cheng)的(de)抽象語法樹(shu)(Abstract Syntax Tree,AST)的(de)解釋執行器,便可以享用(yong)(yong)由 Truffle 提供的(de)各項(xiang)運(yun)行時優(you)化。

就(jiu)一個完整的(de)(de) Truffle 語言(yan)實現(xian)而言(yan),由于實現(xian)本身以及其所依賴的(de)(de) Truffle 框架(jia)部(bu)分都是用 Java 實現(xian)的(de)(de),因此它(ta)可以運行在任何 Java 虛擬(ni)機(ji)之上(shang)。

當(dang)然(ran),如果 Truffle 運行(xing)(xing)在附帶了 Graal 編(bian)(bian)譯器的 Java 虛擬機之上,那么它將(jiang)(jiang)調(diao)用 Graal 編(bian)(bian)譯器所提供的 API,主動觸(chu)發對 Truffle 語言的即時編(bian)(bian)譯,將(jiang)(jiang)對 AST 的解釋(shi)執(zhi)行(xing)(xing)轉換為執(zhi)行(xing)(xing)即時編(bian)(bian)譯后(hou)的機器碼。

目前(qian)除了(le) Java, JavaScript、Ruby、Python 和許多其他流行語言都已經可(ke)以運行在 GraalVM 之上了(le)。

GraalVM 官方(fang)還提(ti)供了完整的文檔,當有(you)一天你開(kai)發(fa)了一款新的語言,也可以用 Truffle 讓它跑在 GraalVM 上。

安裝和使用

GraalVm 目前(qian)的(de)最新版(ban)本是 22.3,分為社區版(ban)和(he)企業版(ban),就好像 OpenJDK 和(he) 商用的(de) Orcale 的(de) JDK ,企業版(ban)會多一(yi)些性(xing)能(neng)分析的(de)功能(neng),用來幫(bang)助更大程(cheng)度的(de)優化性(xing)能(neng)。

社區版是基于OpenJDK 11.0.17, 17.0.5, 19.0.1,而商業版基于Oracle JDK 8u351, 11.0.17, 17.0.5, 19.0.1,所以,如果你想用免費(fei)的,只能將(jiang)程序升級(ji)到 JDK 11 以上(shang)了。

GraalVM 支持 Windows、Linux、MacOS ,可以用(yong)命令安裝最新版,或者(zhe)直(zhi)接下載對(dui)應 Java 版本的。

我是下載的 Java 11 的版本,下載下來的壓縮包,直接解壓,然后配置環境變量。把解壓目錄配置到環境變量的 JAVA_HOME就可以了。

解壓(ya)好其實就相當于安裝(zhuang)完畢了,查看(kan)一下(xia)版本(ben)。

進入到解壓目錄下的bin目錄中,運行 java -version。運行結果如下:

image-20221130105634757

運行代碼

常用方式運行

也就是(shi)我們平時一(yi)直(zhi)在用的這種方式,把 GrralVM 當做 OpenJDK 使用,只不過把即時編譯器換成了 Graal 。就是(shi)前面說的第一(yi)種方式。

安裝完成后,就可以把它當做正常的 JDK 使用了,比如 javacjpsjmap等都可(ke)以直(zhi)接(jie)用(yong)了(le)。大多數人還是用(yong) IDEA 的,所以就直(zhi)接(jie)在 IDEA 中使用(yong)就好(hao)了(le)。

1、先隨意(yi)創建一個 Java 項目。

2、創(chuang)建完(wan)成后,打開項(xiang)目設置。

3、在打開的項目設置彈出框中選擇 SDKs,點擊加號,選擇前面解(jie)壓的 GraalVM 目(mu)錄。

4、然(ran)后(hou)選擇剛剛添加的這個(ge) JDK。

5、最后運(yun)行一段測(ce)試代(dai)碼。

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

上面(mian)這樣的(de)運行(xing)方式(shi),其實就相(xiang)當于(yu)前(qian)面(mian)說的(de)第一種(zhong)運行(xing)方式(shi)

native-image 方式運行

這種方式就是 AOT 編譯成機器碼,已可執行文件的形式出現。native-image 可以命令行的(de)形式執(zhi)行,也可以在配(pei)合(he) Maven 執(zhi)行,我(wo)這兒就(jiu)直接(jie)演示用(yong) Maven 形式的(de)了(le),畢竟(jing)IDEA 搭(da)配(pei) Maven 用(yong)習慣了(le)。

1、安裝native-image 工具包

native-image 是用(yong)來進行 AOT 編譯(yi)打包的(de)(de)工具,先把這個裝上,才能進行后面的(de)(de)步(bu)驟。

安裝好 GraalVM 后,在 bin目錄下有一個叫做 gu的工具,用這個工具安裝,如果將 bin目錄添加到環境中,直(zhi)接下面(mian)的命(ming)令(ling)安裝(zhuang)就行了。

gu install native-image

如果沒有將 bin目錄加到環境變量中,要進入到 bin目錄下(xia),執行下(xia)面的命令安裝。

./gu install native-image

這(zhe)個(ge)過程可能比較慢,因為要去 github 上下載東西,如果一次沒成功(比如超時(shi)),多試兩次就好了。

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是(shi)要用到的(de)編譯為可執行程序的(de) Maven 插件版(ban)本。

imageName是生成(cheng)的可執行程(cheng)序(xu)的名稱。

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 編(bian)譯,打包成本地可執行程序。

執行 Maven 命令

mvn clean package

或者

mvn  -Pnative -Dagent package 

編(bian)(bian)譯打包的(de)過程比(bi)較慢,因為(wei)要(yao)直接(jie)編(bian)(bian)譯成機器碼(ma),所以比(bi)一(yi)(yi)般的(de)編(bian)(bian)譯過程要(yao)慢一(yi)(yi)些(xie)。看到下面的(de)輸入日志(zhi),說明打包成功了。

4、運行可執行程序包,打開 target 目錄,已經看到了graalvm-demo-image可(ke)執行程序包了,大小為 11.58M。

然(ran)后就(jiu)可(ke)以運(yun)行它(ta)了,進入到目錄下(xia)(xia),執行下(xia)(xia)面的命(ming)令運(yun)行,可(ke)以看(kan)到正(zheng)常輸出了。注意了,這(zhe)時(shi)候已經是沒有用(yong)到本地 JVM 了。

./graalvm-demo-image 
Hello GraalVM!

這時候,用 jps -l命令已經看不到這個進程了,只能通過 ps看了。

總結

雖然我們還沒有看到有哪個公司說在用 GraalVM 了,但是 QuarkusSpring BootSpring等(deng)很多(duo)的框架(jia)都已(yi)經支持 GraalVM 的 Native-image 模(mo)式,而且在 Orcale 的大力推廣下(xia)(xia),相信不久之(zhi)后就(jiu)會出現在更(geng)多(duo)的產品中。趕緊體驗(yan)一下(xia)(xia)吧。


如果覺得還不錯的話,給個推薦吧!

公眾號「古時的風箏」,Java 開發者,專注(zhu) Java 及周邊生態。堅(jian)持原創干貨(huo)輸出,你(ni)可選擇(ze)現在就關(guan)(guan)注(zhu)我,或者看看歷史文章再關(guan)(guan)注(zhu)也不(bu)遲。長(chang)按二維碼關(guan)(guan)注(zhu),跟我一起變優(you)秀!

posted @ 2022-12-16 09:29  風的姿態  閱讀(6483)  評論(4)    收藏  舉報