Java >> Java tutorial >  >> JVM

Introduktion til JVM Intrinsics

1. Introduktion

I denne artikel skal vi lære, hvad intrinsics er, og hvordan de fungerer i Java og andre JVM-baserede sprog.

2. Hvad er indre?

En indre funktion er en funktion, der har speciel håndtering af compileren eller fortolkeren til vores programmeringssprog. Mere specifikt er det et særligt tilfælde, hvor compileren eller fortolkeren kan erstatte funktionen med en alternativ implementering af forskellige årsager.

Programmeringssproget håndterer typisk dette ved at forstå, at et bestemt metodekald er specielt, og hver gang vi kalder denne metode, så er den resulterende adfærd anderledes. Dette tillader så, at vores kode ikke ser anderledes ud end normalt, men programmeringssprogets implementering kan gribe ind i særlige tilfælde for at give yderligere fordele.

Den nøjagtige måde, det fungerer på, varierer mellem programmeringssprog og også mellem operativsystemer og hardware. Men fordi disse håndteres for os, behøver vi typisk ikke at kende nogen af ​​disse detaljer.

Intrinsics kan give forskellige fordele. Erstatning af bestemte algoritmer med indbygget kode kan få dem til at yde bedre eller endda udnytte operativsystemets specifikke funktioner eller underliggende hardware.

3. Intrinsics på JVM

JVM implementerer intrinsics ved at erstatte det nøjagtige metodekald på en nøjagtig klasse med en alternativ version. JVM håndterer dette selv, så det vil kun fungere for kerneklasser og bestemte arkitekturer. Det tillader også kun at udskifte visse metoder i stedet for hele klasser.

Præcis hvordan dette fungerer vil variere mellem JVM'er. Dette omfatter ikke kun forskellige versioner af JVM – for eksempel Java 8 vs. Java 11. Dette inkluderer også forskellige JVM-mål - Linux vs. Windows, for eksempel - og især JVM-leverandører - Oracle vs. IBM. I nogle tilfælde kan visse kommandolinjeflag, der sendes til JVM'en, påvirke dem.

Denne variation betyder, at der ikke er nogen måde at bestemme, kun baseret på applikationen, hvilke metoder der vil blive erstattet med iboende, og hvilke der ikke vil. Det vil være anderledes baseret på den JVM, der kører applikationen. Men dette kan i nogle tilfælde føre til overraskende resultater – herunder betydelige præstationsfordele opnået blot ved at ændre den anvendte JVM .

4. Ydeevnefordele

Intrinsics bruges ofte til at implementere en mere effektiv version af den samme kode , for eksempel ved at udnytte implementeringsdetaljerne for det kørende OS eller CPU. Nogle gange skyldes det, at det kan bruge en mere effektiv implementering, og andre gange kan det gå så langt som at bruge hardware-specifik funktionalitet.

For eksempel har HotSpot JDK en iboende implementering for mange af metoderne i java.lang.Math . Afhængigt af den nøjagtige JVM, implementeres disse potentielt ved hjælp af CPU-instruktioner til at udføre de nøjagtige beregninger, der kræves.

En simpel test vil vise dette. Tag for eksempel java.lang.Math.sqrt() . Vi kan skrive en test:

for (int a = 0; a < 100000; ++a) {
    double result = Math.sqrt(a);
}

Denne test udfører en kvadratrodsoperation 100.000 gange, hvilket tager ca. 123ms. Men hvis vi erstatter denne kode med en kopi af implementeringen af ​​Math.sqrt() i stedet:

double result = StrictMath.sqrt(a);

Denne kode gør det samme, men udføres i 166ms i stedet. Det er en stigning på 35 % ved at kopiere implementeringen i stedet for at lade JVM erstatte den med den iboende version.

5. Umulige implementeringer

I andre tilfælde bruges intrinsics til situationer, hvor koden ikke kan implementeres i Java. Disse er typisk forbeholdt sager på meget lavt niveau.

Lad os for eksempel se på metoden onSpinWait() i java.lang.Thread klasse. Denne metode indikerer, at denne tråd i øjeblikket ikke udfører noget arbejde, og at CPU-tid kan gives til en anden tråd. For at implementere dette skal det arbejde på det lavest mulige niveau.

HotSpot JDK til x86-arkitekturer implementerer dette direkte på CPU'en ved hjælp af PAUSE opcode. Den eneste anden måde at opnå dette på ville have været at bruge et JNI-kald til indbygget kode, og de overhead, der er involveret i dette, ville i første omgang besejre fordelene ved opkaldet.

6. Identifikation af indre i Java

Der er desværre ingen garanteret måde at identificere metoder, der kan erstattes med iboende versioner. Dette skyldes, at forskellige JVM'er eller endda den samme JVM på forskellige platforme vil gøre dette til forskellige metoder.

Men når du bruger Hotspot JVM fra Java 9, er @HotSpotIntrinsicCandidate anmærkning bruges på alle metoder, der kan erstattes. Tilføjelse af denne annotering medfører ikke automatisk, at metoden udskiftes. I virkeligheden sker det inden for det underliggende JVM. I stedet ved JVM-udviklere, at disse metoder er specielle og skal være forsigtige med dem.

Andre JVM'er kan håndtere dette anderledes, hvis de overhovedet er identificeret. Dette inkluderer Hotspot JVM i Java 8 eller ældre.

7. Resumé

Vi kan ikke skrive vores programmer, så de er afhængige af tilstedeværelsen af ​​intrinsics, fordi der ikke er nogen måde at vide, om de vil være tilgængelige eller ej på runtime JVM. Men de er en overbevisende tilgang, som JVM kan bruge til at forbedre den måde, programmer fungerer på.

Disse egenskaber kan føjes – og bliver ofte – tilføjet til nyere versioner af JVM. Dette giver altså mulighed for forbedringer af vores allerede kørende kode blot ved at opgradere den JVM, som vi kører på, så dette er endnu en grund til at sikre, at vi holder os ajour med vores afhængigheder og kørselstid.


Java tag