Forstå minnet i JVM

Som du allerede vet, kjører JVM Java-programmer i seg selv. Som enhver virtuell maskin har den sitt eget minneorganisasjonssystem.

Det interne minneoppsettet indikerer hvordan Java-applikasjonen din fungerer. På denne måten kan flaskehalser i driften av applikasjoner og algoritmer identifiseres. La oss se hvordan det fungerer.

Forstå minnet i JVM

Viktig! Den originale Java-modellen var ikke god nok, så den ble revidert i Java 1.5. Denne versjonen brukes til i dag (Java 14+).

Trådstabel

Java-minnemodellen som brukes internt av JVM deler minnet inn i trådstabler og hauger. La oss se på Java-minnemodellen, logisk delt inn i blokker:

Trådstabel

Alle tråder som kjører i JVM har sin egen stack . Stabelen inneholder på sin side informasjon om hvilke metoder tråden har kalt. Jeg vil kalle dette "anropsstakken". Anropsstakken gjenopptas så snart tråden kjører koden sin.

Trådens stabel inneholder alle de lokale variablene som kreves for å utføre metoder på trådens stabel. En tråd kan bare få tilgang til sin egen stabel. Lokale variabler er ikke synlige for andre tråder, bare for tråden som opprettet dem. I en situasjon der to tråder kjører den samme koden, lager de begge sine egne lokale variabler. Dermed har hver tråd sin egen versjon av hver lokale variabel.

Alle lokale variabler av primitive typer ( boolean , byte , short , char , int , long , float , double ) lagres utelukkende på trådstabelen og er ikke synlige for andre tråder. En tråd kan sende en kopi av en primitiv variabel til en annen tråd, men kan ikke dele en primitiv lokal variabel.

Heap

Heapen inneholder alle objektene som er opprettet i applikasjonen din, uavhengig av hvilken tråd som opprettet objektet. Dette inkluderer innpakninger av primitive typer (for eksempel Byte , Integer , Long , og så videre). Det spiller ingen rolle om objektet ble opprettet og tilordnet en lokal variabel eller opprettet som en medlemsvariabel for et annet objekt, det lagres på heapen.

Nedenfor er et diagram som illustrerer anropsstakken og lokale variabler (de er lagret på stabler) samt objekter (de er lagret på haugen):

Heap

I tilfellet hvor den lokale variabelen er av en primitiv type, lagres den på trådens stabel.

En lokal variabel kan også være en referanse til et objekt. I dette tilfellet lagres referansen (lokal variabel) på trådstabelen, men selve objektet lagres på heapen.

Et objekt inneholder metoder, disse metodene inneholder lokale variabler. Disse lokale variablene lagres også på trådstabelen, selv om objektet som eier metoden er lagret på heapen.

Et objekts medlemsvariabler lagres på haugen sammen med selve objektet. Dette gjelder både når medlemsvariabelen er av en primitiv type og når den er en objektreferanse.

Statiske klassevariabler lagres også på haugen sammen med klassedefinisjonen.

Interaksjon med objekter

Objekter på haugen kan nås av alle tråder som har en referanse til objektet. Hvis en tråd har tilgang til et objekt, kan den få tilgang til objektets variabler. Hvis to tråder kaller en metode på samme objekt samtidig, vil de begge ha tilgang til objektets medlemsvariabler, men hver tråd vil ha sin egen kopi av de lokale variablene.

Interaksjon med objekter (heap)

To tråder har et sett med lokale variabler.Lokal variabel 2peker på et delt objekt på haugen (Objekt 3). Hver av trådene har sin egen kopi av den lokale variabelen med sin egen referanse. Referansene deres er lokale variabler og lagres derfor på trådstabler. Imidlertid peker to forskjellige referanser til det samme objektet på haugen.

Vær oppmerksom på at den generelleObjekt 3har lenker tilObjekt 2OgObjekt 4som medlemsvariabler (vist med piler). Gjennom disse lenkene kan to tråder få tilgangObjekt 2OgGjenstand4.

Diagrammet viser også en lokal variabel (lokal variabel 1fra metode to ). Hver kopi av den inneholder forskjellige referanser som peker til to forskjellige objekter (Objekt 1OgObjekt 5) og ikke den samme. Teoretisk sett kan begge trådene få tilgang til beggeObjekt 1, så tilObjekt 5hvis de har referanser til begge disse objektene. Men i diagrammet ovenfor har hver tråd kun en referanse til ett av de to objektene.

Et eksempel på interaksjon med objekter

La oss se hvordan vi kan demonstrere arbeidet 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 kaller one() -metoden , og one() kaller på sin side two() .

One()- metoden erklærer en primitiv lokal variabel (localOne) av typen int og en lokal variabel (localTwo), som er en referanse til et objekt.

Hver tråd som utfører metoden one() vil lage sin egen kopilocalOneOglocalTwoi stabelen din. VariablerlocalOnevil være helt atskilt fra hverandre, og være på stabelen av hver tråd. En tråd kan ikke se hvilke endringer en annen tråd gjør i sin kopilocalOne.

Hver tråd som utfører metoden one() lager også sin egen kopilocalTwo. Dog to forskjellige eksemplarerlocalTwoende opp med å peke på det samme objektet på haugen. Faktum er detlocalTwopeker på objektet som den statiske variabelen refererer tilforekomst. Det er bare én kopi av en statisk variabel, og den kopien er lagret på haugen.

Så begge eksemplarenelocalTwoende opp med å peke på den samme delte forekomsten . Den delte forekomsten lagres også på heapen. Det matcherObjekt 3i diagrammet ovenfor.

Merk at klassen Delt også inneholder to medlemsvariabler. Selve medlemsvariablene lagres på haugen sammen med objektet. To medlemsvariabler peker på to andre objekterHeltall. Disse heltallsobjektene tilsvarerObjekt 2OgObjekt 4på diagrammet.

Vær også oppmerksom på at two() -metoden oppretter en lokal variabel med navnlocalOne. Denne lokale variabelen er en referanse til et objekt av typen Heltall . Metoden setter koblingenlocalOnefor å peke på en ny heltallsforekomst . Linken vil bli lagret i sin kopilocalOnefor hver tråd. To Integer- forekomster vil bli lagret på heapen, og fordi metoden oppretter et nytt Integer- objekt hver gang det kjøres, vil de to trådene som utfører denne metoden lage separate Integer- forekomster . De matcherObjekt 1OgObjekt 5i diagrammet ovenfor.

Legg også merke til de to medlemsvariablene i Delt- klassen av typen Integer , som er en primitiv type. Fordi disse variablene er medlemsvariabler, er de fortsatt lagret på haugen sammen med objektet. Bare lokale variabler lagres på trådstabelen.