Hogyan melegítsük fel a JVM-et

1. Áttekintés

A JVM az egyik legrégebbi, mégis nagy teljesítményű virtuális gép, amelyet valaha gyártottak.

Ebben a cikkben gyorsan áttekintjük, mit jelent a JVM felmelegítése és hogyan kell ezt megtenni.

2. JVM építészeti alapismeretek

Amikor új JVM folyamat indul, az összes szükséges osztályt a ClassLoader egyik példánya tölti be a memóriába. Ez a folyamat három lépésben zajlik:

  1. Bootstrap osztály betöltése: A "Bootstrap osztályú rakodó”Betölti a Java kódot és az alapvető Java osztályokat, mint pl java.lang.Tárgy az emlékezetbe. Ezek a betöltött osztályok JRE \ lib \ rt.jar.
  2. Hosszabbító osztály betöltése: Az ExtClassLoader felelős a JAR fájlok letöltéséért java.ext.dirs pálya. Nem Maven vagy nem Gradle alapú alkalmazásokban, ahol egy fejlesztő manuálisan adja hozzá a JAR-okat, az összes ilyen osztály betöltődik ebben a fázisban.
  3. Alkalmazásosztály betöltése: Az AppClassLoader betölti az alkalmazásosztály elérési útvonalában található összes osztályt.

Ez az inicializálási folyamat egy lusta betöltési sémán alapul.

3. Mi melegíti a JVM-et

Miután az osztálybetöltés befejeződött, az összes fontos osztály (amelyet a folyamat indításakor használtak) a JVM gyorsítótárába (natív kód) tolják - ami gyorsabban elérhetővé teszi őket futás közben. Más osztályok kérésenként kerülnek betöltésre.

A Java webalkalmazáshoz intézett első kérés gyakran lényegesen lassabb, mint a folyamat élettartama alatt az átlagos válaszidő. Ez a bemelegítési időszak általában a lusta osztályterhelésnek és az éppen időben történő összeállításnak tulajdonítható.

Ezt szem előtt tartva, alacsony késleltetésű alkalmazások esetén az összes osztályt előre meg kell tárolnunk gyorsítótárban - hogy futás közben elérhetőek legyenek azonnal.

A JVM hangolásának ezt a folyamatát bemelegítésnek nevezik.

4. Lépcsőzetes összeállítás

A JVM hang architektúrájának köszönhetően a gyakran használt módszerek az alkalmazás életciklusa alatt betöltődnek a natív gyorsítótárba.

Használhatjuk ezt a tulajdonságot arra, hogy a kritikus módszereket kényszerítsük a gyorsítótárba, amikor egy alkalmazás elindul. Ennyire be kell állítanunk egy nevű virtuális gép argumentumot Többszintű összeállítás:

-XX: CompileThreshold -XX: TieredCompilation

Normál esetben a virtuális gép tolmácsot használ a profilkészítő információk gyűjtésére a fordítóba betáplált módszerekről. A többszintű sémában a tolmács mellett a kliens fordítót olyan módszerek összeállított verzióinak előállítására használják, amelyek profilprofil információkat gyűjtenek magukról.

Mivel a lefordított kód lényegesen gyorsabb, mint az értelmezett kód, a program jobb teljesítményt nyújt a profilalkotás során.

A JBoss és a JDK 7-es verzióján futó alkalmazások, amelyeknek engedélyezve van a virtuális gép argumentuma, egy dokumentált hiba miatt általában egy idő után összeomlanak. A problémát a JDK 8-as verziójában javították.

Egy másik szempont, amelyet meg kell jegyezni, hogy a terhelés kényszerítéséhez meg kell győződnünk arról, hogy az összes (vagy a legtöbb) végrehajtandó osztályt elérni kell. Hasonló a kód lefedettségének meghatározásához az egység tesztelése során. Minél több kód van lefedve, annál jobb lesz a teljesítmény.

A következő szakasz bemutatja, hogyan lehet ezt megvalósítani.

5. Kézi megvalósítás

Megvalósíthatunk egy alternatív technikát a JVM felmelegedésére. Ebben az esetben egy egyszerű kézi bemelegítés magában foglalhatja a különböző osztályok létrehozásának többszöri megismétlését, amint az alkalmazás elindul.

Először létre kell hoznunk egy próbabábut normál módszerrel:

public class Dummy {public void m () {}}

Ezután létre kell hoznunk egy olyan statikus metódust, amely legalább 100000-szer végrehajtásra kerül, amint az alkalmazás elindul, és minden egyes végrehajtáskor létrehoz egy új példányt a fent említett dummy osztályból, amelyet korábban létrehoztunk:

public class ManualClassLoader {védett statikus void load () {for (int i = 0; i <100000; i ++) {Dummy dummy = new Dummy (); bábu.m (); }}}

Most annak érdekében mérje meg a teljesítménynövekedést, létre kell hoznunk egy főosztályt. Ez az osztály egy statikus blokkot tartalmaz, amely közvetlen hívást tartalmaz a ManualClassLoader terhelése () módszer.

A fő funkción belül hívunk a ManualClassLoader terhelése () módszerrel, és rögzítse a rendszer idejét nanoszekundumban, közvetlenül a függvényhívásunk előtt és után. Végül kivonjuk ezeket az időket, hogy megkapjuk a tényleges végrehajtási időt.

Kétszer kell futtatnunk az alkalmazást; egyszer a Betöltés() metódushívás a statikus blokkon belül, és egyszer ennek a metódushívásnak a nélkül:

public class MainApplication {static {long start = System.nanoTime (); ManualClassLoader.load (); hosszú vég = System.nanoTime (); System.out.println ("Bemelegedési idő:" + (vég - kezdet)); } public static void main (String [] args) {long start = System.nanoTime (); ManualClassLoader.load (); hosszú vég = System.nanoTime (); System.out.println ("Teljes idő:" + (vég - kezdet)); }}

Az eredmények nanomásodpercekben vannak megadva:

BemelegítésselNincs bemelegítésKülönbség(%)
1220056 8903640 730
1083797 13609530 1256
1026025 9283837 905
1024047 7234871 706
868782 9146180 1053

Ahogy az várható volt, a bemelegítési megközelítés sokkal jobb teljesítményt mutat, mint a normál.

Természetesen ez a nagyon leegyszerűsített referenciaérték és csak némi felszíni szintű betekintést nyújt e technika hatásába. Fontos megérteni azt is, hogy egy valós alkalmazással fel kell melegítenünk a rendszer tipikus kódútjait.

6. Eszközök

Számos eszközt is felhasználhatunk a JVM felmelegedésére. Az egyik legismertebb eszköz a Java Microbenchmark Harness, JMH. Általában mikro-benchmarkinghoz használják. Miután betöltötte, ismételten eltalál egy kódrészletet, és figyeli a bemelegítési iterációs ciklust.

A használatához hozzá kell adnunk egy másik függőséget a pom.xml:

 org.openjdk.jmh jmh-core 1.19 org.openjdk.jmh jmh-generator-annprocess 1.19 

A JMH legújabb verzióját a Central Maven Repository-ban ellenőrizhetjük.

Alternatív megoldásként használhatjuk a JMH maven beépülő modulját egy minta projekt előállításához:

mvn archetípus: generál \ -DinteractiveMode = hamis \ -DarchetypeGroupId = org.openjdk.jmh \ -DarchetypeArtifactId = jmh-java-benchmark-archetype \ -DgroupId = com.baeldung \ -DartifactId = test \ -Dversion = 1.0

Ezután hozzunk létre egy fő- módszer:

public static void main (String [] args) dobja RunnerException, IOException {Main.main (args); }

Most létre kell hoznunk egy módszert, és jegyzettel kell ellátnunk a JMH-val @Viszonyítási alap kommentár:

@Benchmark public void init () {// kódrészlet}

Ezen belül benne módszerrel, olyan kódot kell írnunk, amelyet ismételten végre kell hajtani a bemelegítés érdekében.

7. Teljesítmény benchmark

Az elmúlt 20 évben a Java-hoz való legtöbb hozzájárulás a GC-hez (Garbage Collector) és a JIT-hez (Just In Time Compiler) kapcsolódott. Az interneten talált teljesítmény-referenciaértékek szinte mindegyike egy már régóta futó JVM-en történik. Azonban,

Azonban, Beihang Egyetem összehasonlító jelentést tett közzé, figyelembe véve a JVM bemelegedési idejét. Hadoop és Spark alapú rendszereket használtak hatalmas adatok feldolgozásához:

Itt a HotTub kijelöli azt a környezetet, amelyben a JVM-et melegítették.

Amint láthatja, a gyorsulás jelentős lehet, különösen a viszonylag kicsi olvasási műveleteknél - ezért érdekes ezeket az adatokat figyelembe venni.

8. Következtetés

Ebben a rövid cikkben bemutattuk, hogy a JVM hogyan tölti be az osztályokat, amikor egy alkalmazás elindul, és hogyan melegíthetjük fel a JVM-et teljesítménynövelés érdekében.

Ez a könyv további információkat és irányelveket tartalmaz a témáról, ha folytatni szeretné.

És mint mindig, a teljes forráskód is elérhető a GitHubon.