CodeGym/Java Course/Module 3/Geheugen in de JVM

Geheugen in de JVM

Beschikbaar

Geheugen in de JVM begrijpen

Zoals u al weet, voert de JVM Java-programma's in zichzelf uit. Zoals elke virtuele machine heeft het zijn eigen geheugenorganisatiesysteem.

De lay-out van het interne geheugen geeft aan hoe uw Java-toepassing werkt. Op deze manier kunnen knelpunten in de werking van applicaties en algoritmen worden gesignaleerd. Laten we kijken hoe het werkt.

Geheugen in de JVM begrijpen

Belangrijk! Het originele Java-model was niet goed genoeg, dus werd het herzien in Java 1.5. Deze versie wordt tot op de dag van vandaag gebruikt (Java 14+).

Draadstapel

Het Java-geheugenmodel dat intern door de JVM wordt gebruikt, verdeelt het geheugen in threadstacks en heaps. Laten we eens kijken naar het Java-geheugenmodel, logisch verdeeld in blokken:

Draadstapel

Alle threads die in de JVM draaien hebben hun eigen stack . De stapel bevat op zijn beurt informatie over welke methoden de thread heeft aangeroepen. Ik zal dit de "call-stack" noemen. De call-stack wordt hervat zodra de thread zijn code uitvoert.

De stack van de thread bevat alle lokale variabelen die nodig zijn om methoden uit te voeren op de stack van de thread. Een thread heeft alleen toegang tot zijn eigen stapel. Lokale variabelen zijn niet zichtbaar voor andere threads, alleen voor de thread die ze heeft gemaakt. In een situatie waarin twee threads dezelfde code uitvoeren, creëren ze allebei hun eigen lokale variabelen. Elke thread heeft dus zijn eigen versie van elke lokale variabele.

Alle lokale variabelen van primitieve typen ( boolean , byte , short , char , int , long , float , double ) worden volledig op de threadstack opgeslagen en zijn niet zichtbaar voor andere threads. Een thread kan een kopie van een primitieve variabele doorgeven aan een andere thread, maar kan een primitieve lokale variabele niet delen.

Hoop

De heap bevat alle objecten die in uw toepassing zijn gemaakt, ongeacht door welke thread het object is gemaakt. Dit omvat wrappers van primitieve typen (bijvoorbeeld Byte , Integer , Long , enzovoort). Het maakt niet uit of het object is gemaakt en toegewezen aan een lokale variabele of is gemaakt als een lidvariabele van een ander object, het wordt op de heap opgeslagen.

Hieronder staat een diagram dat de call-stack en lokale variabelen illustreert (ze worden opgeslagen op stapels) en objecten (ze worden opgeslagen op de heap):

Hoop

In het geval dat de lokale variabele van een primitief type is, wordt deze opgeslagen op de threadstack.

Een lokale variabele kan ook een verwijzing naar een object zijn. In dit geval wordt de referentie (lokale variabele) opgeslagen op de threadstack, maar het object zelf wordt opgeslagen op de heap.

Een object bevat methoden, deze methoden bevatten lokale variabelen. Deze lokale variabelen worden ook opgeslagen op de threadstack, zelfs als het object dat eigenaar is van de methode op de heap is opgeslagen.

De lidvariabelen van een object worden samen met het object zelf op de heap opgeslagen. Dit geldt zowel wanneer de lidvariabele van een primitief type is als wanneer het een objectreferentie is.

Statische klassevariabelen worden ook samen met de klassedefinitie op de heap opgeslagen.

Interactie met objecten

Objecten op de heap zijn toegankelijk voor alle threads die een verwijzing naar het object hebben. Als een thread toegang heeft tot een object, dan heeft het toegang tot de variabelen van het object. Als twee threads tegelijkertijd een methode op hetzelfde object aanroepen, hebben ze allebei toegang tot de lidvariabelen van het object, maar elke thread heeft zijn eigen kopie van de lokale variabelen.

Interactie met objecten (heap)

Twee threads hebben een set lokale variabelen.Lokale variabele 2wijst naar een gedeeld object op de heap (Voorwerp 3). Elk van de threads heeft zijn eigen kopie van de lokale variabele met zijn eigen referentie. Hun referenties zijn lokale variabelen en worden daarom opgeslagen op threadstacks. Twee verschillende verwijzingen wijzen echter naar hetzelfde object op de hoop.

Houd er rekening mee dat de generaalVoorwerp 3heeft links naarVoorwerp 2EnVoorwerp 4als lidvariabelen (weergegeven door pijlen). Via deze links hebben twee threads toegangVoorwerp 2EnVoorwerp4.

Het diagram toont ook een lokale variabele (lokale variabele 1van methodeTwo ). Elk exemplaar ervan bevat verschillende referenties die verwijzen naar twee verschillende objecten (Voorwerp 1EnVoorwerp 5) en niet dezelfde. Theoretisch hebben beide threads toegang tot beideVoorwerp 1, dus naarVoorwerp 5als ze verwijzingen naar beide objecten hebben. Maar in het bovenstaande diagram heeft elke thread slechts een verwijzing naar een van de twee objecten.

Een voorbeeld van interactie met objecten

Laten we eens kijken hoe we het werk in code kunnen demonstreren:

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);
}

De methode run() roept de methode one() aan en one() roept op zijn beurt two() aan .

De methode one() declareert een primitieve lokale variabele (localOne) van het type int en een lokale variabele (lokaleTwo), wat een verwijzing is naar een object.

Elke thread die de methode one() uitvoert , maakt zijn eigen kopielocalOneEnlokaleTwoin je stapel. VariabelenlocalOnezullen volledig van elkaar gescheiden zijn, omdat ze zich op de stapel van elke draad bevinden. Een thread kan niet zien welke wijzigingen een andere thread aanbrengt in zijn kopielocalOne.

Elke thread die de methode one() uitvoert , maakt ook zijn eigen kopielokaleTwo. Wel twee verschillende exemplarenlokaleTwouiteindelijk naar hetzelfde object op de hoop wijzen. Het feit is datlokaleTwowijst naar het object waarnaar wordt verwezen door de statische variabelevoorbeeld. Er is slechts één kopie van een statische variabele en die kopie wordt op de heap opgeslagen.

Beide exemplaren duslokaleTwouiteindelijk naar dezelfde gedeelde instantie verwijzen . De gedeelde instantie wordt ook op de heap opgeslagen. Het komt overeenVoorwerp 3in het bovenstaande schema.

Merk op dat de klasse Shared ook twee lidvariabelen bevat. De lidvariabelen zelf worden samen met het object op de heap opgeslagen. Twee lidvariabelen wijzen naar twee andere objectenGeheel getal. Deze gehele objecten komen overeen metVoorwerp 2EnVoorwerp 4op het schema.

Merk ook op dat de methode two() een lokale variabele met de naam maaktlocalOne. Deze lokale variabele is een verwijzing naar een object van het type Integer . De methode legt de linklocalOneom naar een nieuwe Integer- instantie te verwijzen . De link wordt opgeslagen in de kopielocalOnevoor elke draad. Er worden twee Integer- instanties op de heap opgeslagen en omdat de methode elke keer dat deze wordt uitgevoerd een nieuw Integer- object maakt , maken de twee threads die deze methode uitvoeren afzonderlijke Integer- instanties . Ze komen overeenVoorwerp 1EnVoorwerp 5in het bovenstaande schema.

Let ook op de twee lidvariabelen in de klasse Shared van het type Integer , wat een primitief type is. Omdat deze variabelen lidvariabelen zijn, worden ze nog steeds samen met het object op de heap opgeslagen. Alleen lokale variabelen worden opgeslagen op de threadstack.

Opmerkingen
  • Populair
  • Nieuw
  • Oud
Je moet ingelogd zijn om opmerkingen te kunnen maken
Deze pagina heeft nog geen opmerkingen