Az idő összeállítása előtt (AoT)

1. Bemutatkozás

Ebben a cikkben megnézzük a Java Ahead of Time (AOT) fordítót, amelyet a JEP-295 ismertet, és amelyet a Java 9 kísérleti funkciójaként adtak hozzá.

Először meglátjuk, mi az AOT, másodszor pedig megnézünk egy egyszerű példát. Harmadszor, meglátjuk az AOT néhány korlátozását, végül pedig megvitatunk néhány lehetséges felhasználási esetet.

2. Mi áll az idő összeállítása előtt?

Az AOT-fordítás a Java programok teljesítményének és különösen a JVM indítási idejének javításának egyik módja. A JVM végrehajtja a Java bájtkódot, és a gyakran végrehajtott kódot natív kódra fordítja. Ezt hívják Just-in-Time (JIT) összeállításnak. A JVM a végrehajtás során összegyűjtött profilok alapján dönti el, hogy a JIT mely kódot állítja össze.

Míg ez a technika lehetővé teszi a JVM számára, hogy nagyon optimalizált kódot állítson elő, és javítja a csúcsteljesítményt, az indítási idő valószínűleg nem optimális, mivel a végrehajtott kódot még nem állították össze a JIT. Az AOT célja ennek az úgynevezett bemelegedési időszaknak a javítása. Az AOT-hoz használt fordító Graal.

Ebben a cikkben nem vizsgáljuk meg részletesen a JIT-et és a Graalt. Kérjük, olvassa el a többi cikkünket, hogy áttekintse a Java 9 és 10 teljesítménybeli fejlesztéseit, valamint mély elmélyülést a Graal JIT Compiler-ben.

3. Példa

Ebben a példában egy nagyon egyszerű osztályt fogunk használni, lefordítjuk és megtudjuk, hogyan kell használni a kapott könyvtárat.

3.1. AOT összeállítás

Vessünk egy gyors pillantást a minta osztályunkra:

JaotCompilation nyilvános osztály {public static void main (String [] argv) {System.out.println (message ()); } public static String message () {return "A JAOT fordító" Hello "-t mond; }} 

Az AOT fordító használata előtt le kell fordítanunk az osztályt a Java fordítóval:

javac JaotCompilation.java 

Ezután átadjuk az eredményt JaotCompilation.class az AOT fordítóhoz, amely ugyanabban a könyvtárban található, mint a szokásos Java fordító:

jaotc --output jaotCompilation.so JaotCompilation.class 

Ez hozza létre a könyvtárat jaotCompilation.so az aktuális könyvtárban.

3.2. A program futtatása

Ezután futtathatjuk a programot:

java -XX: AOTLibrary =. / jaotCompilation.so JaotCompilation 

A vita -XX: AOTLibrary elfogad egy rokon vagy teljes utat a könyvtárhoz. Alternatív megoldásként átmásolhatjuk a könyvtárat a lib mappát, és csak a könyvtár nevét adja át.

3.3. A könyvtár hívásának és használatának ellenőrzése

Láthatjuk, hogy a könyvtár valóban kiegészítéssel lett betöltve -XX: + PrintAOT JVM-érvként:

java -XX: + PrintAOT -XX: AOTLibrary =. / jaotCompilation.so JaotCompilation 

A kimenet a következőképpen fog kinézni:

77 1 betöltve ./jaotCompilation.so aot könyvtár 

Ez azonban csak arról árulkodik, hogy a könyvtár betöltődött, de nem arról, hogy valóban használták volna. Az érvelés átadásával -bőbeszédű, láthatjuk, hogy a könyvtárban található módszereket valóban hívják:

java -XX: AOTLibrary =. / jaotCompilation.so -verbose -XX: + PrintAOT JaotCompilation 

A kimenet a következő sorokat tartalmazza:

11 1 betöltve ./jaotCompilation.so aot könyvtár 116 1 aot [1] jaotc.JaotCompilation. () V 116 2 aot [1] jaotc.JaotCompilation.message () Ljava / lang / String; 116 3 aot [1] jaotc.JaotCompilation.main ([Ljava / lang / String;) V A JAOT fordító azt mondja: „Hello” 

Az AOT által összeállított könyvtár tartalmazza a osztályú ujjlenyomat, amelynek meg kell egyeznie a .osztály fájl.

Változtassuk meg az osztály kódját JaotCompilation.java egy másik üzenet visszaadásához:

public static String message () {return "A JAOT fordító azt mondja:" Jó reggelt ""; } 

Ha úgy hajtjuk végre a programot, hogy az AOT a módosított osztályt nem fordítja le:

java -XX: AOTLibrary =. / jaotCompilation.so -verbose -XX: + PrintAOT JaotCompilation 

Ekkor a kimenet csak a következőket tartalmazza:

 11 1 betöltve ./jaotCompilation.so aot könyvtár A JAOT fordító azt mondja: "Jó reggelt"

Láthatjuk, hogy a könyvtárban lévő módszerek nem lesznek meghívva, mivel az osztály bájtkódja megváltozott. Ennek az az ötlete, hogy a program mindig ugyanazt az eredményt fogja produkálni, függetlenül attól, hogy az AOT által összeállított könyvtár be van-e töltve vagy sem.

4. További AOT és JVM érvek

4.1. AOT Java modulok összeállítása

Az AOT is összeállíthat egy modult:

jaotc --output javaBase.so - modul java.base 

Az így létrejött könyvtár javaBase.so kb. 320 MB méretű, és egy kis időbe telik a betöltése. A méret csökkenthető az AOT által összeállítandó csomagok és osztályok kiválasztásával.

Az alábbiakban megvizsgáljuk, hogyan lehet ezt megtenni, azonban nem merülünk el mélyen az összes részletben.

4.2. Szelektív fordítás Compile parancsokkal

Annak megakadályozása érdekében, hogy egy Java modul AOT által lefordított könyvtára túl nagy legyen, hozzáadhatunk fordítási parancsokat, hogy korlátozzuk az AOT fordításának hatókörét. Ezeknek a parancsoknak szöveges fájlban kell lenniük - példánkban a fájlt fogjuk használni complileCommands.txt:

csak java.lang. *

Ezután hozzáadjuk a compile parancshoz:

jaotc --output javaBaseLang.so - modul java.base --compile-commands compileCommands.txt 

A kapott könyvtár csak az AOT által összeállított osztályokat fogja tartalmazni a csomag java.lang.

Ahhoz, hogy valódi teljesítményjavulást érjünk el, meg kell találnunk, hogy mely osztályokat hívják meg a JVM bemelegítése során.

Ez több JVM-argumentum hozzáadásával érhető el:

java -XX: + UnlockDiagnosticVMOptions -XX: + LogTouchedMethods -XX: + PrintTouchedMethodsAtExit JaotCompilation 

Ebben a cikkben nem merülünk el mélyebben ebben a technikában.

4.3. AOT egyetlen osztály összeállítása

Az argumentummal egyetlen osztályt állíthatunk össze -osztály név:

jaotc --output javaBaseString.so - class-name java.lang.String 

A kapott könyvtár csak az osztályt fogja tartalmazni Húr.

4.4. Fordítsd a Tiered számára

Alapértelmezés szerint mindig az AOT által összeállított kódot kell használni, és a könyvtárban szereplő osztályok esetében nem történik JIT fordítás. Ha be akarjuk vonni a profilalkotási információkat a könyvtárba, hozzáadhatjuk az argumentumot többszintű összeállítás:

jaotc --output jaotCompilation.so - compile-for-szintes JaotCompilation.class 

A könyvtárban előre lefordított kód addig lesz használva, amíg a bájtkód jogosulttá válik a JIT fordítására.

5. Lehetséges felhasználási esetek az AOT összeállításához

Az AOT egyik használati esete a rövid futó programok, amelyek befejezik a végrehajtást, mielőtt bármilyen JIT-fordítás megtörténne.

Egy másik felhasználási eset a beágyazott környezetek, ahol a JIT nem lehetséges.

Ezen a ponton azt is meg kell jegyeznünk, hogy az AOT által lefordított könyvtár csak azonos bájtkódú Java osztályból tölthető be, tehát nem tölthető be JNI-n keresztül.

6. AOT és az Amazon Lambda

Az AOT által összeállított kód egyik lehetséges felhasználási esete a rövid élettartamú lambda függvények, ahol fontos a rövid indítási idő. Ebben a szakaszban megvizsgáljuk, hogyan futtathatjuk az AOT által összeállított Java kódot az AWS Lambda-n.

Az AOT-összeállítás használata az AWS Lambda szolgáltatással megköveteli, hogy a könyvtárat az AWS-en használt operációs rendszerrel kompatibilis operációs rendszerre kell építeni. Az írás idején ez Amazon Linux 2.

Továbbá a Java verziónak meg kell egyeznie. Az AWS biztosítja a Amazon Corretto Java 11 JVM. Annak érdekében, hogy legyen környezetünk a könyvtárunk összeállításához, telepítjük Amazon Linux 2 és Amazon Corretto a Dockerben.

Nem tárgyaljuk a Docker és az AWS Lambda használatának minden részletét, csak a legfontosabb lépéseket vázoljuk fel. A Docker használatáról további információt itt talál a hivatalos dokumentációban.

Ha többet szeretne megtudni a Lambda függvény Java-val történő létrehozásáról, olvassa el az AWS Lambda With Java cikkünket.

6.1. Fejlesztési környezetünk konfigurálása

Először meg kell húznunk a Docker képet Amazon Linux 2 és telepítse Amazon Corretto:

# Töltse le az Amazon Linux dokkolót az amazonlinux behúzására # a Docker konténer belsejébe, telepítse az Amazon Corretto-t yum install java-11-amazon-corretto # néhány további könyvtár szükséges a jaotc yum install binutils.x86_64 

6.2. Összeállítja az osztályt és a könyvtárat

A Docker-tárolón belül a következő parancsokat hajtjuk végre:

# mappa létrehozása aot mkdir aot cd aot mkdir jaotc cd jaotc

A mappa neve csak egy példa, és természetesen bármilyen más név lehet.

package jaotc; public class JaotCompilation {public static int message (int input) {return input * 2; }}

A következő lépés az osztály és a könyvtár összeállítása:

javac JaotCompilation.java cd .. jaotc -J-XX: + UseSerialGC --output jaotCompilation.so jaotc / JaotCompilation.class

Itt fontos, hogy ugyanazt a szemétgyűjtőt használja, mint az AWS-en. Ha könyvtárunkat nem lehet betölteni az AWS Lambda-ra, akkor a következő paranccsal érdemes ellenőriznünk, hogy melyik szemétgyűjtőt használják valójában:

java -XX: + PrintCommandLineFlags -verzió

Most létrehozhatunk egy ZIP-fájlt, amely tartalmazza a könyvtárunkat és az osztályfájlunkat:

zip -r jaot.zip jaotCompilation.so jaotc /

6.3. Konfigurálja az AWS Lambda szolgáltatást

Az utolsó lépés a bejelentkezés az AWS Lamda konzolba, a zip fájl feltöltése és a Lambda konfigurálása a következő paraméterekkel:

  • Futásidő: Java 11
  • Kezelő: jaotc.JaotCompilation :: üzenet

Ezenkívül létre kell hoznunk egy JAVA_TOOL_OPTIONS nevű környezeti változót, amelynek értékét a következőkre kell beállítani:

-XX: + UnlockExperimentalVMOptions -XX: + PrintAOT -XX: AOTLibrary =. / JaotCompilation.so

Ez a változó lehetővé teszi a paraméterek átadását a JVM számára.

Az utolsó lépés a Lambda bemenetének konfigurálása. Az alapértelmezett egy JSON bemenet, amelyet nem lehet átadni a függvényünknek, ezért azt String-re kell állítanunk, amely egész számot tartalmaz, pl. „1”.

Végül végre tudjuk hajtani a Lambda függvényünket, és látnunk kell a naplóban, hogy az AOT által összeállított könyvtárunk betöltődött:

57 1 betöltött ./jaotCompilation.so aot könyvtár

7. Következtetés

Ebben a cikkben azt láttuk, hogy az AOT hogyan fordíthatja le a Java osztályokat és modulokat. Mivel ez még mindig kísérleti szolgáltatás, az AOT fordító nem része az összes disztribúciónak. Valódi példákat még mindig ritkán találunk, és a Java közösség feladata lesz megtalálni a legjobb felhasználási eseteket az AOT alkalmazásához.

A cikk összes kódrészlete megtalálható a GitHub-adattárunkban.


$config[zx-auto] not found$config[zx-overlay] not found