Forståelse af hukommelse i JVM
Som du allerede ved, kører JVM Java-programmer i sig selv. Som enhver virtuel maskine har den sit eget hukommelsesorganisationssystem.
Det interne hukommelseslayout angiver, hvordan din Java-applikation fungerer. På denne måde kan flaskehalse i driften af applikationer og algoritmer identificeres. Lad os se, hvordan det virker.
Vigtig! Den originale Java-model var ikke god nok, så den blev revideret i Java 1.5. Denne version bruges den dag i dag (Java 14+).
Tråd stak
Java-hukommelsesmodellen, der bruges internt af JVM, opdeler hukommelsen i trådstakke og dynger. Lad os se på Java-hukommelsesmodellen, logisk opdelt i blokke:
Alle tråde , der kører i JVM'en, har deres egen stack . Stakken rummer til gengæld information om, hvilke metoder tråden har kaldt. Jeg vil kalde dette "opkaldsstakken". Opkaldsstakken genoptages, så snart tråden udfører sin kode.
Trådens stak indeholder alle de lokale variabler , der kræves for at udføre metoder på trådens stak. En tråd kan kun få adgang til sin egen stack. Lokale variabler er ikke synlige for andre tråde, kun for den tråd, der skabte dem. I en situation, hvor to tråde udfører den samme kode, opretter de begge deres egne lokale variable. Således har hver tråd sin egen version af hver lokale variabel.
Alle lokale variabler af primitive typer ( boolean , byte , short , char , int , long , float , double ) lagres udelukkende på trådstakken og er ikke synlige for andre tråde. Én tråd kan sende en kopi af en primitiv variabel til en anden tråd, men kan ikke dele en primitiv lokal variabel.
Dynge
Heapen indeholder alle de objekter, der er oprettet i din applikation, uanset hvilken tråd, der oprettede objektet. Dette inkluderer indpakninger af primitive typer (f.eks. Byte , Integer , Long , og så videre). Det er lige meget, om objektet blev oprettet og tildelt til en lokal variabel eller oprettet som en medlemsvariabel af et andet objekt, det gemmes på heapen.
Nedenfor er et diagram, der illustrerer opkaldsstakken og lokale variabler (de er gemt på stakke) samt objekter (de er gemt på heapen):
I det tilfælde, hvor den lokale variabel er af en primitiv type, gemmes den på trådens stak.
En lokal variabel kan også være en reference til et objekt. I dette tilfælde er referencen (lokal variabel) gemt på trådstakken, men selve objektet gemmes på heapen.
Et objekt indeholder metoder, disse metoder indeholder lokale variabler. Disse lokale variabler gemmes også på trådstakken, selvom objektet, der ejer metoden, er gemt på heapen.
Et objekts medlemsvariabler gemmes på heapen sammen med selve objektet. Dette gælder både når medlemsvariablen er af en primitiv type, og når den er en objektreference.
Statiske klassevariabler gemmes også på heapen sammen med klassedefinitionen.
Interaktion med objekter
Objekter på heapen kan tilgås af alle tråde, der har en reference til objektet. Hvis en tråd har adgang til et objekt, så kan den få adgang til objektets variabler. Hvis to tråde kalder en metode på det samme objekt på samme tid, vil de begge have adgang til objektets medlemsvariabler, men hver tråd vil have sin egen kopi af de lokale variable.
To tråde har et sæt lokale variabler.Lokal variabel 2peger på et delt objekt på heapen (Objekt 3). Hver af trådene har sin egen kopi af den lokale variabel med sin egen reference. Deres referencer er lokale variabler og gemmes derfor på trådstakke. To forskellige referencer peger dog på det samme objekt på bunken.
Bemærk venligst, at den almObjekt 3har links tilObjekt 2OgObjekt 4som medlemsvariable (vist med pile). Gennem disse links kan to tråde få adgangObjekt 2OgObjekt4.
Diagrammet viser også en lokal variabel (lokal variabel 1fra metode to ). Hver kopi af den indeholder forskellige referencer, der peger på to forskellige objekter (Objekt 1OgObjekt 5) og ikke den samme. Teoretisk set kan begge tråde få adgang til beggeObjekt 1, så tilObjekt 5hvis de har referencer til begge disse objekter. Men i diagrammet ovenfor har hver tråd kun en reference til et af de to objekter.
Et eksempel på interaktion med objekter
Lad os se, hvordan vi kan demonstrere arbejdet i kode:
public class MySomeRunnable implements Runnable() {
public void run() {
one();
}
public void one() {
int localOne = 1;
Shared localTwo = Shared.instance;
//... do something with local variables
two();
}
public void two() {
Integer localOne = 2;
//... do something with local variables
}
}
public class Shared {
// store an instance of our object in a variable
public static final Shared instance = new Shared();
// member variables pointing to two objects on the heap
public Integer object2 = new Integer(22);
public Integer object4 = new Integer(44);
}
Run()- metoden kalder one() -metoden , og one() kalder igen two() .
One() metoden erklærer en primitiv lokal variabel (localOne) af typen int og en lokal variabel (localTo), som er en reference til et objekt.
Hver tråd, der udfører metoden one() vil skabe sin egen kopilocalOneOglocalToi din stak. VariablerlocalOnevil være fuldstændig adskilt fra hinanden, idet de er på stakken af hver tråd. En tråd kan ikke se, hvilke ændringer en anden tråd foretager i sin kopilocalOne.
Hver tråd, der udfører metoden one() opretter også sin egen kopilocalTo. Dog to forskellige eksemplarerlocalToende med at pege på det samme objekt på dyngen. Faktum er, atlocalTopeger på objektet, der refereres til af den statiske variabeleksempel. Der er kun én kopi af en statisk variabel, og denne kopi er gemt på heapen.
Så begge kopierlocalToende med at pege på den samme delte forekomst . Den delte forekomst gemmes også på heapen. Det matcherObjekt 3i diagrammet ovenfor.
Bemærk, at klassen Shared også indeholder to medlemsvariabler. Selve medlemsvariablerne gemmes på heapen sammen med objektet. To medlemsvariabler peger på to andre objekterHeltal. Disse heltalsobjekter svarer tilObjekt 2OgObjekt 4på diagrammet.
Bemærk også, at metoden two() opretter en lokal variabel med navnetlocalOne. Denne lokale variabel er en reference til et objekt af typen Heltal . Metoden sætter linketlocalOneat pege på en ny Integer- forekomst . Linket vil blive gemt i sin kopilocalOnefor hver tråd. To Integer- forekomster vil blive gemt på heapen, og fordi metoden opretter et nyt Integer- objekt hver gang det udføres, vil de to tråde, der udfører denne metode, skabe separate Integer- forekomster . De matcherObjekt 1OgObjekt 5i diagrammet ovenfor.
Læg også mærke til de to medlemsvariabler i Shared- klassen af typen Integer , som er en primitiv type. Fordi disse variabler er medlemsvariabler, gemmes de stadig på heapen sammen med objektet. Kun lokale variabler gemmes på trådstakken.
GO TO FULL VERSION