ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 148
Numărul 147 Numărul 146 Numărul 145 Numărul 144 Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 143
Abonament PDF

Compilarea AOT în Java

Alin Bobeica
Java Software Engineer @ Accesa



PROGRAMARE

Modul în care construim aplicații software a evoluat din 1995, când a fost introdus pentru prima dată Java, ca limbaj de programare. Am progresat de la utilizarea monoliților, la microservicii și, în ultimii ani, la serverless. Cu toate acestea, aceste schimbări aduc, de asemenea, noi provocări, cum ar fi timpul de pornire rapid și instant peak performance, esențiale pentru dezvoltarea aplicațiilor software. Pentru a aborda aceste provocări, Java a introdus Native Images.

Ce sunt Native Images?

Native Images desemnează o tehnologie care utilizează compilarea ahead-of-time pentru a transforma codul Java în executabile autonome numite native images. Acest lucru duce la timpi de pornire mai mici, o utilizare mai eficientă a resurselor și o securitate îmbunătățită.

Compilarea ahead-of-time (AOT)

În aplicațiile Java tradiționale, metoda de compilare utilizată este just-in-time (JIT). JVM este responsabil de executarea bytecode-ului Java și de compilarea codului utilizat frecvent în native code pe baza informațiilor rezultate în urma profilingului din timpul execuției. Avantajul acestui tip de compilare este că permite ca JVM-ul să livreze cod optimizat pentru îmbunătățirea performanțelor de vârf și pentru așa-numita aplicație platform-independent. Dar aceste avantaje vin și cu anumite dezavantaje: JIT folosește mult JVM în timpul execuției, ceea ce duce la un timp de pornire mai mare și la introducerea unui warm-up time. În plus, JIT necesită un JVM pentru a executa codul, ceea ce implică o utilizare crescută a resurselor și la o amprentă de memorie mai mare. AOT urmărește să îmbunătățească aceste aspecte.

Ahead-of-time compilation se referă la tehnica de traducere a unui limbaj high-level, în cazul nostru Java, într-un limbaj low-level, înainte ca aplicația să fie executată, de regulă, la build time. Rezultatul AOT va fi un binar, specific platformei utilizate pentru compilare, care nu necesită compilare ulterioară. 

Compilarea AOT este utilizată în aplicațiile Java pentru a îmbunătăți performanța generală, dar, mai ales, pentru a reduce timpul de pornire. Cel mai cunoscut compilator AOT în Java este GraalVM.

GraalVM

GraalVM a început ca un proiect de cercetare la Oracle, în cadrul ramurii de cercetare și dezvoltare a companiei, Oracle Labs. Oracle Labs este responsabil de cercetarea limbajelor de programare, a mașinilor virtuale, învățarea automată, securitate, procesare grafică și alte domenii. 

Principalul produs al GraalVM este compilatorul Graal, un compilator cu optimizare ridicată, creat de la zero. În mod surprinzător, acest compilator este scris în cea mai mare parte în Java și, în multe scenarii, datorită numeroaselor optimizări, este mai performant decât compilatorul C2. Acest lucru demonstrează încă o dată cât de puternic este Java ca limbaj de programare.

Cum funcționează?

GraalVM primește ca input bytecode-ul Java și generează un executabil. Acest executabil este specific platformei utilizate pentru compilare. Cum face GraalVM acest lucru? Ei bine, realizează ceva numit analiză statică, în care compilatorul analizează codul folosit în aplicație și include doar acel cod în rezultatul nativ. 

Pentru a face acest lucru, compilatorul utilizează aceste trei tehnici:

Aceste trei etape se repetă până când se ajunge la un punct fix, unde toate clasele și metodele necesare rulării aplicației au fost incluse.

Pentru a suporta funcționalități cum ar fi gestionarea memoriei și programarea firelor de execuție, Native Images includ un lightweight VM numit SubstrateVM. Acest VM special este, de asemenea, scris în Java.

Fig. 1 Proces de compilare GraalVM

Care sunt beneficiile imaginilor native?

Native images au mai multe avantaje. Câteva dintre principalele avantaje ale utilizării lor sunt:

Exemplu de native image cu Spring Native

În cele ce urmează, o să analizăm un exemplu simplu ce folosește Spring Native și Maven pentru construirea de native images. Pentru aceasta, voi folosi ediția Community GraalVM, care se bazează pe OpenJDK. Versiunea Java utilizată pentru acest exemplu este 21. GraalVM vine, de asemenea, cu un plugin Maven ce facilitează crearea și testarea executabilelor native. Spring Native este un proiect din cadrul Spring Framework care oferă suport pentru crearea aplicațiilor Spring ca imagini native.

Fig. 2 JIT vs. AOT startup

Am scris o aplicație simplă pentru gestionarea produselor, care expune 4 endpoint-uri pentru crearea, ștergerea și listarea produselor. Vom crea două versiuni ale acestei aplicații, una compilată JIT, care rulează folosind JVM și cealaltă va fi compilată AOT, ca imagine nativă, apoi voi compara performanța acestor două aplicații.

În primul rând, trebuie să adăugăm pluginul graalVM în pom.xml - acest lucru ne va oferi capacitatea de a crea imagini native folosind Maven.

<build>
  <plugins>
    <plugin>
      <groupId>org.graalvm.buildtools</groupId>
      <artifactId>native-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>

Acum, să compilăm aplicația folosind comanda maven:

./mvnw -Pnative native:compile

După ce compilarea este finalizată, putem observa imaginea nativă sub forma unui executabil.

Timp de pornire: Deoarece codul Java nu trebuie interpretat și compilat, imaginea nativă pornește imediat în comparație cu aplicația JVM. De asemenea, datorită heapului prepopulat și compilării directe în cod mașină, aplicația funcționează la performanțe maxime.

În imaginile de mai jos, putem vedea logurile din timpul pornirii aplicațiilor Spring, timpul de pornire al aplicației compilată ca imagine nativă a avut timpul de pornire de doar 143 ms, în timp ce timpul de pornire al aplicației ce rulează folosind JVM este de 2,834 secunde.

Eficientizarea resurselor. Deoarece codul java este compilat în avans, executabilul nativ nu are nevoie de JVM, de infrastructura de compilare JIT a acestuia sau de memorie pentru codul compilat, ci are nevoie de memorie doar pentru executabil și pentru datele aplicației.

Fig. 3. 1 Native Image startup log

Fig. 3.2 JVM application startup log

Graficele reflectă consumul de CPU și al memoriei celor două aplicații. Linia albastră reprezintă utilizarea memoriei, aproximativ 390 MB pentru aplicația JVM față de 120 MB pentru imaginea nativă. Linia roșie reprezintă activitatea procesorului. Putem observa că aplicația JVM consumă mult mai mult CPU în timpul perioadei de warm-up, din cauza tuturor operațiunilor JIT care trebuie efectuate; pe de altă parte, imaginea nativă utilizează mult mai puțin CPU, toate operațiunile ce necesită putere de procesare intensivă efectuându-se în timpul compilării.

Dezavantaje ale imaginilor native

Probabil că acum putem spune că este prea frumos pentru a fi adevărat, dar imaginile native vin și cu unele dezavantaje și lucruri de care trebuie să ținem cont atunci când lucrăm cu acestea în Java. 

Iată câteva dezavantaje ale imaginilor native:

Fig. 4 Native Image vs. JVM, consum cpu și memorie

Concluzie

În concluzie, introducerea imaginilor native în Java marchează un progres semnificativ în abordarea provocărilor aplicațiilor moderne, cum ar fi timpii de pornire rapizi și utilizarea eficientă a resurselor. Prin utilizarea compilării ahead-of-time și a tehnologiilor precum GraalVM, dezvoltatorii Java pot produce acum executabile independente cu performanțe ridicate și o amprentă de memorie redusă.

Beneficiile imaginilor native, inclusiv timpul de pornire instant, utilizarea optimizată a resurselor și vulnerabilitatea redusă fac din acestea o opțiune pentru aplicațiile cu durată de viață scurtă și pentru cele care necesită măsuri de securitate mai bune. Cu toate acestea, este esențial să recunoaștem dezavantajele asociate cu imaginile native, cum ar fi creșterea build time-ului, suportul limitat pentru reflection și problemele de compatibilitate cu anumite funcționalități și librării Java. Abordarea acestor provocări poate necesita un efort suplimentar și o analiză atentă în timpul dezvoltării.

În timp ce imaginile native oferă avantaje promițătoare, dezvoltatorii ar trebui să evalueze adecvarea lor pentru proiecte specifice pe baza cerințelor de performanță, a considerentelor de compatibilitate și a constrângerilor de resurse. Cu o înțelegere adecvată a provocărilor potențiale, imaginile native pot fi un instrument valoros în dezvoltarea aplicațiilor Java moderne, permițând o performanță și o scalabilitate îmbunătățite în diverse medii de implementare.

Referințe

  1. Alina Yurenko, Revolutionizing Java with GraalVM Native Image

  2. Points to Analysis

  3. Class Initialization in Native Image

Conferință TSM

NUMĂRUL 147 - Automotive

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects