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:
- 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.
- 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.
- 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éssel | Nincs bemelegítés | Kü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.