Stapelspeicher und Heapspeicher in Java

1. Einleitung

Um eine Anwendung optimal auszuführen, unterteilt JVM den Speicher in Stapel- und Heapspeicher. Immer wenn wir neue Variablen und Objekte deklarieren, eine neue Methode aufrufen, einen String deklarieren oder ähnliche Operationen ausführen, bestimmt JVM diesen Operationen Speicher entweder aus dem Stapelspeicher oder aus dem Heap-Speicher.

In diesem Tutorial werden diese Speichermodelle erläutert. Wir werden einige wichtige Unterschiede zwischen ihnen auflisten, wie sie im RAM gespeichert sind, welche Funktionen sie bieten und wo sie verwendet werden.

2. Stapeln Sie den Speicher in Java

Der Stapelspeicher in Java wird für die statische Speicherzuweisung und die Ausführung eines Threads verwendet. Es enthält methodenspezifische Grundwerte und Verweise auf Objekte in einem Heap, auf die von der Methode verwiesen wird.

Der Zugriff auf diesen Speicher erfolgt in der Reihenfolge Last-In-First-Out (LIFO). Bei jedem Aufruf einer neuen Methode wird ein neuer Block über dem Stapel erstellt, der methodenspezifische Werte wie primitive Variablen und Verweise auf Objekte enthält.

Wenn die Ausführung der Methode abgeschlossen ist, wird der entsprechende Stapelrahmen geleert, der Fluss kehrt zur aufrufenden Methode zurück und es wird Speicherplatz für die nächste Methode verfügbar.

2.1. Hauptmerkmale des Stapelspeichers

Abgesehen von dem, was wir bisher besprochen haben, sind im Folgenden einige andere Merkmale des Stapelspeichers aufgeführt:

  • Es wächst und schrumpft, wenn neue Methoden aufgerufen bzw. zurückgegeben werden
  • Variablen innerhalb des Stapels existieren nur, solange die Methode ausgeführt wird, mit der sie erstellt wurden
  • Es wird automatisch zugewiesen und freigegeben, wenn die Ausführung der Methode abgeschlossen ist
  • Wenn dieser Speicher voll ist, löst Java java.lang.StackOverFlowError aus
  • Der Zugriff auf diesen Speicher ist im Vergleich zum Heap-Speicher schnell
  • Dieser Speicher ist threadsicher, da jeder Thread in einem eigenen Stapel arbeitet

3. Heap Space in Java

Der Heap-Speicherplatz in Java wird zur Laufzeit für die dynamische Speicherzuweisung für Java-Objekte und JRE-Klassen verwendet . Neue Objekte werden immer im Heap-Bereich erstellt und die Verweise auf diese Objekte werden im Stapelspeicher gespeichert.

Diese Objekte haben globalen Zugriff und können von überall in der Anwendung aus aufgerufen werden.

Dieses Speichermodell ist weiter in kleinere Teile unterteilt, die als Generationen bezeichnet werden. Dies sind:

  1. Junge Generation - hier werden alle neuen Objekte zugeordnet und gealtert. Eine kleine Garbage Collection tritt auf, wenn diese voll ist
  2. Alte oder Tenured Generation - hier werden lange überlebende Objekte aufbewahrt. Wenn Objekte in der jungen Generation gespeichert werden, wird ein Schwellenwert für das Alter des Objekts festgelegt, und wenn dieser Schwellenwert erreicht ist, wird das Objekt in die alte Generation verschoben
  3. Permanente Generierung - Diese besteht aus JVM-Metadaten für die Laufzeitklassen und Anwendungsmethoden

Diese verschiedenen Teile werden auch in diesem Artikel behandelt - Unterschied zwischen JVM, JRE und JDK.

Wir können die Größe des Heapspeichers jederzeit gemäß unseren Anforderungen ändern. Weitere Informationen finden Sie in diesem verlinkten Baeldung-Artikel.

3.1. Hauptmerkmale des Java-Heapspeichers

Abgesehen von dem, was wir bisher besprochen haben, sind im Folgenden einige andere Merkmale des Heapspeichers aufgeführt:

  • Der Zugriff erfolgt über komplexe Speicherverwaltungstechniken wie Young Generation, Old oder Tenured Generation und Permanent Generation
  • Wenn der Heapspeicher voll ist, löst Java java.lang.OutOfMemoryError aus
  • Der Zugriff auf diesen Speicher ist relativ langsamer als der Stapelspeicher
  • Dieser Speicher wird im Gegensatz zum Stapel nicht automatisch freigegeben. Garbage Collector muss nicht verwendete Objekte freigeben, um die Effizienz der Speichernutzung zu gewährleisten
  • Im Gegensatz zu Stack ist ein Heap nicht threadsicher und muss durch ordnungsgemäße Synchronisierung des Codes geschützt werden

4. Beispiel

Basierend auf dem, was wir bisher gelernt haben, analysieren wir einen einfachen Java-Code und bewerten, wie der Speicher hier verwaltet wird:

class Person { int id; String name; public Person(int id, String name) { this.id = id; this.name = name; } } public class PersonBuilder { private static Person buildPerson(int id, String name) { return new Person(id, name); } public static void main(String[] args) { int id = 23; String name = "John"; Person person = null; person = buildPerson(id, name); } }

Lassen Sie uns dies Schritt für Schritt analysieren:

  1. Bei Eingabe der main () -Methode wird ein Speicherplatz im Stapelspeicher erstellt, um Grundelemente und Referenzen dieser Methode zu speichern
    • Der Grundwert der Ganzzahl- ID wird direkt im Stapelspeicher gespeichert
    • Die Referenzvariable Person vom Typ Person wird ebenfalls im Stapelspeicher erstellt, der auf das tatsächliche Objekt im Heap verweist
  2. Der Aufruf des parametrisierten Konstruktors Person (int, String) von main () reserviert weiteren Speicher über dem vorherigen Stapel. Dies speichert:
    • Die this- Objektreferenz des aufrufenden Objekts im Stapelspeicher
    • Die primitive Wert- ID im Stapelspeicher
    • Die Referenzgröße von String - Argumente Namen , der auf die tatsächliche Zeichenfolge aus Zeichenfolge - Pool in Heap - Speicher Punkt
  3. Die Hauptmethode ruft ferner die statische Methode buildPerson () auf , für die eine weitere Zuordnung im Stapelspeicher zusätzlich zur vorherigen erfolgt. Dadurch werden wieder Variablen auf die oben beschriebene Weise gespeichert.
  4. Doch für die neu erstellte Objekt Person vom Typ Person , werden alle Instanzvariablen in Heap - Speicher gespeichert werden.

Diese Zuordnung wird in diesem Diagramm erläutert:

5. Zusammenfassung

Bevor wir diesen Artikel abschließen, lassen Sie uns die Unterschiede zwischen dem Stapelspeicher und dem Heap-Bereich kurz zusammenfassen:

Parameter Stapelspeicher Haufenraum
Anwendung Der Stapel wird in Teilen einzeln während der Ausführung eines Threads verwendet Die gesamte Anwendung verwendet zur Laufzeit Heap-Speicherplatz
Größe Der Stapel hat je nach Betriebssystem Größenbeschränkungen und ist normalerweise kleiner als Heap Es gibt keine Größenbeschränkung für Heap
Lager Speichert nur primitive Variablen und Verweise auf Objekte, die im Heap Space erstellt wurden Alle neu erstellten Objekte werden hier gespeichert
Auftrag Der Zugriff erfolgt über das LIFO-Speicherzuweisungssystem (Last-In First-Out) Auf diesen Speicher wird über komplexe Speicherverwaltungstechniken zugegriffen, die die junge Generation, die alte oder die dauerhafte Generation und die permanente Generation umfassen.
Leben Der Stapelspeicher ist nur vorhanden, solange die aktuelle Methode ausgeführt wird Heap-Speicherplatz ist vorhanden, solange die Anwendung ausgeführt wird
Effizienz Im Vergleich zu Heap ist die Zuweisung vergleichsweise viel schneller Im Vergleich zum Stapel langsamer zuzuordnen
Zuteilung / Freigabe Dieser Speicher wird automatisch zugewiesen und freigegeben, wenn eine Methode aufgerufen bzw. zurückgegeben wird Heap-Speicherplatz wird zugewiesen, wenn neue Objekte von Gargabe Collector erstellt und freigegeben werden, wenn nicht mehr auf sie verwiesen wird

6. Fazit

Stapel und Heap sind zwei Möglichkeiten, wie Java Speicher zuweist. In diesem Artikel haben wir verstanden, wie sie funktionieren und wann sie für die Entwicklung besserer Java-Programme verwendet werden müssen.

Weitere Informationen zur Speicherverwaltung in Java finden Sie in diesem Artikel hier. Wir haben auch den JVM Garbage Collector besprochen, auf den in diesem Artikel kurz eingegangen wird.