Metodeindfletning i JVM

1. Introduktion

I denne tutorial tager vi et kig på, hvilken metode indlejring er i Java Virtual Machine, og hvordan den fungerer.

Vi vil også se, hvordan man får og læser de oplysninger, der er relateret til inline fra JVM, og hvad vi kan gøre med disse oplysninger for at optimere vores kode.

2. Hvilken metode er der?

I bund og grund, inlining er en måde at optimere kompileret kildekode ved kørsel ved at erstatte påkaldelsen af ​​de oftest udførte metoder med dens kroppe.

Selvom der er involveret kompilering, udføres det ikke af det traditionelle javac compiler, men af ​​selve JVM. For at være mere præcis, det er ansvaret for Just-In-Time (JIT) kompilatoren, som er en del af JVM; javac producerer kun en bytecode og lader JIT gøre magien og optimere kildekoden.

En af de vigtigste konsekvenser af denne tilgang er, at hvis vi kompilerer koden ved hjælp af gammel Java, er det samme.klasse filen vil være hurtigere på nyere JVM'er. På denne måde behøver vi ikke at kompilere kildekoden igen, men kun opdatere Java.

3. Hvordan JIT gør det?

I det væsentlige er den JIT-kompilator forsøger at integrere de metoder, som vi ofte kalder, så vi kan undgå omkostningerne ved en metodeopkald. Det tager to ting i betragtning, når man beslutter, om man skal integrere en metode eller ej.

For det første bruger det tællere til at holde styr på, hvor mange gange vi påberåber metoden. Når metoden kaldes mere end et bestemt antal gange, bliver den “varm”. Denne tærskel er som standard indstillet til 10.000, men vi kan konfigurere den via JVM-flag under Java-opstart. Vi ønsker bestemt ikke at integrere alt, da det ville være tidskrævende og ville producere en enorm bytekode.

Vi skal huske på, at inline kun finder sted, når vi kommer til en stabil tilstand. Dette betyder, at vi bliver nødt til at gentage udførelsen flere gange for at give nok profiloplysninger til JIT-kompilatoren.

Desuden garanterer det at være “hot” ikke, at metoden vil blive angivet. Hvis det er for stort, vil JIT ikke integrere det. Den acceptable størrelse er begrænset af -XX: FreqInlineSize = flag, som angiver det maksimale antal instruktioner for bytecode, der skal integreres for en metode.

Ikke desto mindre anbefales det stærkt ikke at ændre standardværdien af ​​dette flag, medmindre vi er helt sikre på at vide, hvilken indvirkning det kan have. Standardværdien afhænger af platformen - for 64-bit Linux er den 325.

JIT indbygges statisk, privat, eller endelig metoder generelt. Og mens offentlig metoder er også kandidater til inline, ikke alle offentlige metoder vil nødvendigvis være angivet. JVM skal bestemme, at der kun er en enkelt implementering af en sådan metode. Enhver yderligere underklasse ville forhindre inline, og ydeevnen vil uundgåeligt falde.

4. Finde varme metoder

Vi vil bestemt ikke gætte, hvad JIT laver. Derfor har vi brug for en eller anden måde at se, hvilke metoder der er inline eller ikke inline. Vi kan let opnå dette og logge alle disse oplysninger til standardoutputtet ved at indstille nogle ekstra JVM-flag under opstart:

-XX: + PrintCompilation -XX: + UnlockDiagnosticVMOptions -XX: + PrintInlining

Det første flag logger, når JIT-kompilering sker. Det andet flag muliggør yderligere flag inklusive -XX: + PrintInlining, som vil udskrive, hvilke metoder der bliver inline, og hvor.

Dette viser os de inline-metoder i form af et træ. Bladene er kommenteret og markeret med en af ​​følgende muligheder:

  • inline (hot) - denne metode er markeret som varm og er inline
  • for stor - metoden er ikke varm, men også den genererede bytecode er for stor, så den er ikke inline
  • varm metode for stor - dette er en varm metode, men den er ikke inline, da bytekoden er for stor

Vi skal være opmærksomme på den tredje værdi og forsøge at optimere metoder med etiketten "hot metode for stor".

Generelt, hvis vi finder en varm metode med en meget kompleks betinget erklæring, skal vi prøve at adskille indholdet af hvis-erklæring og øge granulariteten, så JIT kan optimere koden. Det samme gælder for kontakt og til-loop udsagn.

Vi kan konkludere, at en manuel metodeindlejring er noget, vi ikke behøver at gøre for at optimere vores kode. JVM gør det mere effektivt, og vi vil muligvis gøre koden lang og vanskelig at følge.

4.1. Eksempel

Lad os nu se, hvordan vi kan kontrollere dette i praksis. Vi opretter først en simpel klasse, der beregner summen af ​​den første N fortløbende positive heltal:

offentlig klasse ConsecutiveNumbersSum {private long totalSum; private int totalNumbers; public ConsecutNumbersSum (int totalNumbers) {this.totalNumbers = totalNumbers; } offentlig lang getTotalSum () {totalSum = 0; for (int i = 0; i <totalNumbers; i ++) {totalSum + = i; } returnere totalSum; }}

Dernæst bruger en enkel metode klassen til at udføre beregningen:

privat statisk lang beregneSum (int n) {returner nye konsekutive numreSum (n) .getTotalSum (); }

Endelig kalder vi metoden flere gange og ser hvad der sker:

for (int i = 1; i <NUMBERS_OF_ITERATIONS; i ++) {calcSum (i); }

I det første løb vil vi køre det 1.000 gange (mindre end tærskelværdien på 10.000 nævnt ovenfor). Hvis vi søger i output for beregneSum () metode, finder vi den ikke. Dette forventes, da vi ikke kaldte det nok gange.

Hvis vi nu ændrer antallet af iterationer til 15.000 og søger i output igen, ser vi:

664 262% com.baeldung.inlining.InliningExample :: main @ 2 (21 bytes) @ 10 com.baeldung.inlining.InliningExample :: calcSum (12 bytes) inline (hot)

Vi kan se, at denne gang metoden opfylder betingelserne for indlejring, og JVM har skitseret den.

Det er bemærkelsesværdigt at nævne igen, at hvis metoden er for stor, vil JIT ikke integrere den, uanset antallet af gentagelser. Vi kan kontrollere dette ved at tilføje et andet flag, når vi kører applikationen:

-XX: FreqInlineSize = 10

Som vi kan se i den foregående output, er størrelsen på vores metode 12 bytes. Det -XX:FreqInlineSize flag vil begrænse den metodestørrelse, der er berettiget til indlejring, til 10 byte. Følgelig bør indlægningen ikke finde sted denne gang. Og faktisk kan vi bekræfte dette ved at kigge igen på output:

330 266% com.baeldung.inlining.InliningExample :: main @ 2 (21 bytes) @ 10 com.baeldung.inlining.InliningExample :: calcSum (12 bytes) varm metode for stor

Selvom vi har ændret flagværdien her til illustration, skal vi understrege anbefalingen om ikke at ændre standardværdien af -XX: FreqInlineSize flag, medmindre det er absolut nødvendigt.

5. Konklusion

I denne artikel så vi, hvilken metode indlejring er i JVM, og hvordan JIT gør det. Vi beskrev, hvordan vi kan kontrollere, om vores metoder er kvalificerede til indlejring eller ej, og foreslog, hvordan vi bruger disse oplysninger ved at forsøge at reducere størrelsen på ofte kaldte lange metoder, der er for store til at blive inline.

Endelig illustrerede vi, hvordan vi i praksis kan identificere en varm metode.

Alle de kodestykker, der er nævnt i artiklen, kan findes i vores GitHub-arkiv.