Hvordan varme opp JVM

1. Oversikt

JVM er en av de eldste, men kraftige virtuelle maskinene som noensinne er bygget.

I denne artikkelen ser vi raskt på hva det vil si å varme opp en JVM og hvordan du gjør det.

2. Grunnleggende om JVM-arkitektur

Hver gang en ny JVM-prosess starter, blir alle nødvendige klasser lastet inn i minnet av en forekomst av ClassLoader. Denne prosessen foregår i tre trinn:

  1. Bootstrap Class Loading: Bootstrap Class Loader”Laster Java-kode og viktige Java-klasser som java.lang.Objekt inn i minnet. Disse lastede klassene bor i JRE \ lib \ rt.jar.
  2. Lasting av utvidelsesklasse: ExtClassLoader er ansvarlig for å laste alle JAR-filer som ligger på java.ext.dirs sti. I ikke-Maven eller ikke-Gradle-baserte applikasjoner, der en utvikler legger til JARer manuelt, lastes alle disse klassene i løpet av denne fasen.
  3. Søknadsklasse Laster: AppClassLoader laster inn alle klassene som ligger i programklassestien.

Denne initialiseringsprosessen er basert på en lazy loading-ordning.

3. Hva varmer opp JVM

Når klasselastingen er fullført, skyves alle viktige klasser (brukt på tidspunktet for prosessstart) inn i JVM-hurtigbufferen (opprinnelig kode) - noe som gjør dem tilgjengelige raskere under kjøretiden. Andre klasser lastes inn per forespørsel.

Den første forespørselen til en Java-webapplikasjon er ofte vesentlig langsommere enn den gjennomsnittlige responstiden i løpet av prosessens levetid. Denne oppvarmingsperioden kan vanligvis tilskrives lasting av lat klasse og just-in-time kompilering.

Med tanke på dette, for applikasjoner med lav latens, må vi cache alle klasser på forhånd - slik at de er tilgjengelige umiddelbart når de åpnes i løpetid.

Denne prosessen med å stille inn JVM er kjent som oppvarming.

4. Tiered Compilation

Takket være lydarkitekturen til JVM lastes ofte brukte metoder inn i den opprinnelige hurtigbufferen i løpet av applikasjonens livssyklus.

Vi kan bruke denne egenskapen til å tvinge inn viktige metoder i hurtigbufferen når et program starter. I den grad må vi angi et VM-argument som heter Trinnvis kompilering:

-XX: CompileThreshold -XX: TieredCompilation

Normalt bruker VM tolken til å samle inn profileringsinformasjon om metoder som mates inn i kompilatoren. I den trinnvise ordningen, i tillegg til tolken, brukes klientkompilatoren til å generere kompilerte versjoner av metoder som samler inn profileringsinformasjon om seg selv.

Siden kompilert kode er vesentlig raskere enn tolket kode, kjøres programmet med bedre ytelse under profileringsfasen.

Programmer som kjører på JBoss og JDK versjon 7 med dette VM-argumentet aktivert, har en tendens til å krasje etter en stund på grunn av en dokumentert feil. Problemet er løst i JDK versjon 8.

Et annet poeng å merke seg her er at for å tvinge belastning, må vi sørge for at alle (eller de fleste) klassene som skal utføres må få tilgang. Det ligner på å bestemme kodedekning under enhetstesting. Jo mer kode dekkes, desto bedre blir ytelsen.

Neste avsnitt viser hvordan dette kan implementeres.

5. Manuell implementering

Vi kan implementere en alternativ teknikk for å varme opp JVM. I dette tilfellet kan en enkel manuell oppvarming inkludere å gjenta oppretting av forskjellige klasser tusenvis av ganger så snart applikasjonen starter.

For det første må vi lage en dummy-klasse med en vanlig metode:

offentlig klasse Dummy {public void m () {}}

Deretter må vi lage en klasse som har en statisk metode som vil bli utført minst 100000 ganger så snart applikasjonen starter, og med hver utførelse oppretter den en ny forekomst av den nevnte dummy-klassen vi opprettet tidligere:

offentlig klasse ManualClassLoader {beskyttet statisk tomrombelastning () {for (int i = 0; i <100000; i ++) {Dummy dummy = new Dummy (); dummy.m (); }}}

Nå, for å måle ytelsesgevinsten, må vi lage en hovedklasse. Denne klassen inneholder en statisk blokk som inneholder en direkte samtale til ManualClassLoader last () metode.

Inne i hovedfunksjonen ringer vi til ManualClassLoader last () metoden en gang til og fange systemtiden i nanosekunder like før og etter funksjonsanropet vårt. Til slutt trekker vi fra disse tidene for å få den faktiske utførelsestiden.

Vi må kjøre applikasjonen to ganger; en gang med laste() metode samtale inne i den statiske blokken og en gang uten denne metoden samtale:

offentlig klasse MainApplication {statisk {lang start = System.nanoTime (); ManualClassLoader.load (); lang ende = System.nanoTime (); System.out.println ("Oppvarmingstid:" + (slutt - start)); } public static void main (String [] args) {long start = System.nanoTime (); ManualClassLoader.load (); lang ende = System.nanoTime (); System.out.println ("Total tid tatt:" + (slutt - start)); }}

Nedenfor er resultatene gjengitt i nanosekunder:

Med oppvarmingIngen oppvarmingForskjell(%)
1220056 8903640 730
1083797 13609530 1256
1026025 9283837 905
1024047 7234871 706
868782 9146180 1053

Som forventet, med oppvarmingsmetoden viser mye bedre ytelse enn den vanlige.

Selvfølgelig er dette en veldig forenklet målestokk og gir bare litt innsikt på overflatenivå i virkningen av denne teknikken. Det er også viktig å forstå at vi med en virkelig applikasjon trenger å varme opp med de typiske kodestiene i systemet.

6. Verktøy

Vi kan også bruke flere verktøy for å varme opp JVM. Et av de mest kjente verktøyene er Java Microbenchmark Harness, JMH. Det brukes vanligvis til mikrobenchmarking. Når den er lastet, den treffer gjentatte ganger et kodebit og overvåker oppvarmingssyklusen.

For å bruke det må vi legge til en annen avhengighet til pom.xml:

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

Vi kan sjekke den nyeste versjonen av JMH i Central Maven Repository.

Alternativt kan vi bruke JMHs maven-plugin til å generere et prøveprosjekt:

mvn arketype: generer \ -DinteractiveMode = falsk \ -DarchetypeGroupId = org.openjdk.jmh \ -DarchetypeArtifactId = jmh-java-benchmark-arketype \ -DgroupId = com.baeldung \ -DartifactId = test \ -Dversion = 1.0

La oss deretter lage en hoved- metode:

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

Nå må vi lage en metode og kommentere den med JMH-er @Benchmark kommentar:

@Benchmark public void init () {// kodebit}

Inne i dette i det metoden, må vi skrive kode som må utføres gjentatte ganger for å varme opp.

7. Benchmark for ytelse

De siste 20 årene var de fleste bidrag til Java relatert til GC (Garbage Collector) og JIT (Just In Time Compiler). Nesten alle ytelsesverdiene som er funnet på nettet, er gjort på en JVM som allerede kjører i noen tid. Derimot,

Derimot, Beihang universitet har publisert en referanserapport som tar hensyn til JVM-oppvarmingstid. De brukte Hadoop og Spark-baserte systemer for å behandle massive data:

Her betegner HotTub miljøet der JVM ble oppvarmet.

Som du kan se, kan hastigheten være betydelig, spesielt for relativt små leseoperasjoner - det er derfor disse dataene er interessante å vurdere.

8. Konklusjon

I denne raske artikkelen viste vi hvordan JVM laster inn klasser når en applikasjon starter, og hvordan vi kan varme opp JVM for å få et ytelsesløft.

Denne boka går over mer informasjon og retningslinjer om emnet hvis du vil fortsette.

Og som alltid er hele kildekoden tilgjengelig på GitHub.


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