Java Stack vs. Heap: Praktischer Leitfaden zur Speicherallokation
Was ist Stack-Speicher?
In Java ist der Stack ein zusammenhängender Speicherbereich, der Methodenaufruf-Frames, lokale Variablen und Referenzvariablen hält. Jedes Mal, wenn eine Methode aufgerufen wird, wird ein neuer Frame auf den Stack gelegt. Der Stack-Speicher ist Last-In-First-Out (LIFO) organisiert, was bedeutet, dass der jüngste Aufruf der erste ist, der beim Methodenreturn entfernt wird.
Was ist Heap-Speicher?
Der Heap ist der Bereich, in dem Java-Objekte erstellt werden. Er hält alle Instanzen von Klassen und optional Referenzvariablen, die auf diese Objekte zeigen. Im Gegensatz zum Stack ist der Heap nicht an die Lebensdauer eines einzelnen Methodenaufrufs gebunden, was Objekten erlaubt, über den Gültigkeitsbereich hinaus zu bestehen, in dem sie erstellt wurden.
Speicherallokation in Java
Speicherallokation in Java bezeichnet den Prozess der Reservierung von virtuellem Speicher für Programmdaten. Variablen werden nicht bei der Deklaration allokiert; stattdessen wird eine Referenz erstellt. Wenn der new-Operator verwendet wird, allokiert die JVM Speicher auf dem Heap für das Objekt.
Java teilt den Speicher in vier verschiedene Abschnitte für effizientes Management:
- Heap
- Stack
- Code (Bytecode)
- Static (Klassendaten)
- Der Code-Abschnitt enthält den kompilierten Bytecode.
- Der Stack hält Methoden-Frames, lokale Variablen und Referenzvariablen.
- Der Heap speichert Objekte und gelegentlich Referenzvariablen.
- Der Static-Abschnitt hält statische Felder und Methoden.
Lokale vs. Instanzvariablen
Instanzvariablen werden innerhalb einer Klasse, aber außerhalb jeder Methode deklariert:
class Student {
int num; // Instanzvariable
public void showData() {}
}
Lokale Variablen werden innerhalb einer Methode (oder als Methodenparameter) deklariert:
public void sum(int a) {
int x = a + 3; // a und x sind lokale Variablen
}
Stack vs. Heap in Aktion
Lassen Sie uns ein Beispiel durchgehen, um zu veranschaulichen, wie Stack und Heap während Methodenaufrufen interagieren.
Angenommen, die main-Methode ruft m1() auf:
public void m1() {
int x = 20;
}
Ein Frame für m1 wird auf den Stack gelegt. Die lokale Variable x wird in diesem Frame gespeichert.

Wenn m1 m2(int b) aufruft, wird ein neuer Frame oben auf m1's Frame gelegt:
public void m2(int b) {
boolean c;
}

Ebenso ruft m2 m3() auf, was einen weiteren Frame erstellt:

Innerhalb von m3 wird ein Account-Objekt auf dem Heap instanziiert, während seine Referenz ref auf dem Stack lebt:
class Account {
int p;
int q;
}
public void m3() {
Account ref = new Account(); // zusätzlicher Code
}

Die Referenzvariable ref wird in m3's Stack-Frame erstellt und zeigt auf das heap-allokierte Account-Objekt.

Wenn m3 abgeschlossen ist, wird sein Stack-Frame entfernt, wodurch das Account-Objekt ohne Referenzen zurückbleibt. Es wird für Garbage Collection berechtigt.

Derselbe Prozess wiederholt sich für m2 und m1, bis die Kontrolle an main zurückgegeben wird.
Objektreferenzen als Instanzvariablen
Betrachten Sie eine Klasse A, die eine Referenz auf eine Instanz von B hält:
public static void main(String[] args) {
A parent = new A(); // zusätzlicher Code
}
class A {
B child = new B();
int e;
}
class B {
int c;
int d;
}
Hier wird die child-Referenz auf dem Heap als Teil des A-Objekts gespeichert und zeigt auf seine eigene B-Instanz.

Wichtigste Erkenntnisse
- Jeder Methodenaufruf erstellt einen neuen Frame auf dem Stack.
- Lokale Variablen liegen auf dem Stack; Instanzvariablen auf dem Heap.
- Referenzvariablen werden auf dem Stack gespeichert, zeigen aber auf Heap-Objekte.
- Wenn ein Stack-Frame entfernt wird, werden seine lokalen und Referenzvariablen verworfen, und verwaiste Heap-Objekte werden für Garbage Collection berechtigt.
Java
- Java Variablen und Literale: Umfassender Leitfaden
- Java Klassen und Objekte: Praktischer Leitfaden
- Java abstrakte Klassen und Methoden: Ein umfassender Leitfaden
- Java verschachtelte und innere Klassen meistern: Typen, Beispiele und Best Practices
- Java throw vs. throws: Exception Handling mit praktischen Beispielen meistern
- Java Annotation Types: Umfassender Leitfaden zu vordefinierten, benutzerdefinierten und Meta-Annotations
- Java Autoboxing und Unboxing meistern: Praktische Beispiele und Best Practices
- Java String-Ersetzung meistern: replace(), replaceAll() und replaceFirst() erklärt
- Java Methoden überschreiben: Superclass-Verhalten anpassen
- Java 10: Heap auf alternativen Speicher (NV-DIMM) allozieren – JEP 316