Enige tijd geleden schreef ik een paar berichten over Java Garbage Collection en Java is Pass by Value. Daarna kreeg ik veel e-mails om uit te leggen over Java Heap Space, Java Stack Memory, Memory Allocation in Java en wat de verschillen tussen hen zijn. Je zult veel verwijzingen naar Heap- en Stack-geheugen zien in Java, Java EE-boeken en tutorials, maar nauwelijks een volledige uitleg van wat Heap- en Stack-geheugen is in termen van een programma.
Java Heap Space
Java Heap Space wordt door Java-runtime gebruikt om geheugen toe te wijzen aan objecten en JRE-klassen. Telkens wanneer we een object maken, wordt het altijd in de Heap-ruimte gemaakt. Garbage Collection wordt uitgevoerd op het heap-geheugen om het geheugen vrij te maken dat wordt gebruikt door objecten zonder enige referentie. Elk object dat in de heap-ruimte is gemaakt, heeft wereldwijde toegang en kan worden gerefereerd vanuit elke locatie van de toepassing.
Java Stack Memory
Java Stack-geheugen wordt gebruikt voor de uitvoering van een thread. Ze bevatten methode-specifieke waarden die kortstondig zijn en verwijzingen naar andere objecten in de heap die worden aangeroepen vanuit de methode. Het stack-geheugen wordt altijd aangeroepen in LIFO (Last-In-First-Out) volgorde. Telkens wanneer een methode wordt aangeroepen, wordt er een nieuw blok gecreëerd in het stack-geheugen voor de methode om lokale primitieve waarden en verwijzingen naar andere objecten in de methode vast te houden. Zodra de methode eindigt, wordt het blok ongebruikt en beschikbaar voor de volgende methode. De grootte van het stack-geheugen is veel kleiner in vergelijking met het heap-geheugen.
Heap- en Stack-geheugen in Java-programma
Laten we het gebruik van het heap- en stack-geheugen begrijpen aan de hand van een eenvoudig programma.
package com.journaldev.test;
public class Memory {
public static void main(String[] args) { // Line 1
int i=1; // Line 2
Object obj = new Object(); // Line 3
Memory mem = new Memory(); // Line 4
mem.foo(obj); // Line 5
} // Line 9
private void foo(Object param) { // Line 6
String str = param.toString(); //// Line 7
System.out.println(str);
} // Line 8
}
De onderstaande afbeelding toont het stack- en heap-geheugen met betrekking tot het bovenstaande programma en hoe ze worden gebruikt om primitieve waarden, objecten en referentievariabelen op te slaan. Laten we de stappen van de uitvoering van het programma doornemen.
- Zodra we het programma uitvoeren, laadt het alle Runtime-klassen in de heap-ruimte. Wanneer de main() methode wordt gevonden op regel 1, maakt Java Runtime stack-geheugen aan dat wordt gebruikt door de main() methode-thread.
- We creëren een primitieve lokale variabele op regel 2, dus deze wordt aangemaakt en opgeslagen in het stackgeheugen van de methode main().
- Aangezien we een Object aanmaken in de 3e regel, wordt deze aangemaakt in het heapgeheugen en bevat het stackgeheugen de referentie hiernaar. Een soortgelijk proces doet zich voor wanneer we een Memory-object aanmaken in de 4e regel.
- Wanneer we nu de methode foo() aanroepen in de 5e regel, wordt er een blok boven aan de stack gecreëerd dat door de methode foo() wordt gebruikt. Omdat Java pass-by-value is, wordt er een nieuwe referentie naar het Object aangemaakt in het stackblok van foo() in de 6e regel.
- A string is created in the 7th line, it goes in the String Pool in the heap space and a reference is created in the foo() stack space for it.
- De methode foo() wordt beëindigd in de 8e regel, op dit moment wordt het geheugenblok dat voor foo() is toegewezen in de stack vrijgegeven.
- In regel 9 wordt de methode main() beëindigd en wordt het stackgeheugen dat is aangemaakt voor de methode main() vernietigd. Ook eindigt het programma op deze regel, waardoor de Java Runtime al het geheugen vrijmaakt en de uitvoering van het programma beëindigt.
Verschil tussen Java Heap-ruimte en Stack-geheugen
Op basis van de bovenstaande uitleg kunnen we gemakkelijk de volgende verschillen tussen Heap- en Stack-geheugen concluderen.
- Heap-geheugen wordt gebruikt door alle delen van de toepassing, terwijl stack-geheugen alleen wordt gebruikt door één uitvoeringsdraad.
- Wanneer een object wordt gemaakt, wordt het altijd opgeslagen in de Heap-ruimte en de stack-geheugenruimte bevat de verwijzing ernaar. Stackgeheugen bevat alleen lokale primitieve variabelen en verwijzingsvariabelen naar objecten in de heap-ruimte.
- Objecten die zijn opgeslagen in de heap zijn wereldwijd toegankelijk, terwijl het stackgeheugen niet toegankelijk is voor andere threads.
- Geheugenbeheer in de stack gebeurt op een LIFO-manier, terwijl het complexer is in de heap-geheugenruimte omdat het wereldwijd wordt gebruikt. Heap-geheugen is verdeeld in Young-Generation, Old-Generation, enzovoort, meer details zijn te vinden op Java Garbage Collection.
- Stackgeheugen is van korte duur, terwijl heapgeheugen vanaf het begin tot het einde van de uitvoering van de toepassing blijft bestaan.
- We kunnen de JVM-opties -Xms en -Xmx gebruiken om de opstartgrootte en maximale grootte van het heapgeheugen te definiëren. We kunnen -Xss gebruiken om de grootte van het stackgeheugen te definiëren.
- Wanneer het stackgeheugen vol is, gooit de Java-runtime een
java.lang.StackOverFlowError
, terwijl als het heapgeheugen vol is, het een foutjava.lang.OutOfMemoryError: Java Heap Space
geeft. - De grootte van het stackgeheugen is veel kleiner in vergelijking met het heapgeheugen. Vanwege de eenvoud in geheugenallocatie (LIFO) is stackgeheugen zeer snel in vergelijking met heapgeheugen.
Dat is alles voor Java Heap Space vs Stack Memory wat betreft de Java-toepassing, ik hoop dat het je twijfels over geheugenallocatie zal wegnemen wanneer een Java-programma wordt uitgevoerd.
Referentie: https://nl.wikipedia.org/wiki/Java_Memory_Model.
Source:
https://www.digitalocean.com/community/tutorials/java-heap-space-vs-stack-memory