Garbage Collection

Garbage Collection und Java Virtual Machine

Alle erzeugten Objekte werden im Heap-Speicher der JVM (Java Virtual Machine) abgelegt. Da aber dieser Speicherbereich nicht unendlich groß ist, müssen die nicht mehr benötigten Objekte wieder entfernt werden. Diese Aufgabe könnte uns als Entwickler obliegen. Doch wir haben Glück: Java kennt eine automatische Speicherbereinigung, die Garbage Collection (Übersetzt: Müllabfuhr). Alle nicht referenzierten Objekte werden aus dem Heap-Speicher entfernt.
Trotzdem kann es durch unachtsame Programmierung zu Speicherlecks (Memory Leaks) kommen. Wenn eine nicht mehr benötigte Referenz noch ein Objekt, dies kann auch eine sehr große Collection sein, referenziert, wird dieses Objekt eben nicht aus dem Speicher entfernt.

Beispiel

Anhand eines kleinen Beispiels möchte ich die Garbage Collection erläutern:

public class Person {

  private String name;

  private Person partner;

  public Person( String name ) { this.name = name; }

  public Person getPartner() { return partner;       }

  public void setPartner(Person partner) { this.partner = partner; }

  public static void main(String[] args) {

    Person [ ] personen = { new Person( "Margit"), new Person("Hans" ) };

  }

}

Anschließend wollen wir unserer Person Margit einen Partner zuweisen.

public static void main(String[] args) {

  Person [ ] personen = { new Person("Margit"), new Person("Hans") };

 

  personen[0].setPartner( personen[1] );

}

Was passiert aber, wenn wir das Array an der Stelle 0 mit null initialisieren?

public static void main(String[] args) {

  Person [ ] personen = { new Person("Margit"), new Person("Hans") };

 

  personen[0].setPartner( personen[1] );

           

  personen[0] = null;

}

Arbeitsweise

Der Garbage Collector wird ausgehend von unserer Klasse Person auf dem Stack die main-Methode untersuchen. Welche Objekte können von hier erreicht werden? Über die lokale Variable personen wird das Array erreicht. An der Stelle 1 im Array wird die Person Hans referenziert und somit werden weder das Array noch die Person Hans aus dem Heap-Speicher entfernt. Der Speicher der Person Margit ist ohne Referenzierung und wird somit freigegeben.

Wie sieht es im nächsten Fall aus?

public static void main(String[] args) {

  Person [ ] personen = { new Person("Margit"), new Person("Hans") };

  personen[0].setPartner( personen[1] );

  personen[1].setPartner( personen[0] );

}

Nun initialisieren wir die lokale Variable personen mit null.

public static void main(String[] args) {

  Person [ ] personen = { new Person("Margit"), new Person("Hans") };

  personen[0].setPartner( personen[1] );

  personen[1].setPartner( personen[0] );

            

  personen = null;

}

Jetzt sieht die Sache etwas anders aus. Der Garbage Collector beginnt in der main-Methode und findet die null-Referenz in der lokalen Variablen personen, Somit ist von hier kein Objekt erreichbar. Obwohl Margit und auch Hans jeweils referenziert sind, werden sie aus dem Heap-Speicher entfernt, da sie aus der main-Methode unerreichbar sind.

 

Im nächsten Beispiel sehen wir eine zusätzliche lokale Variable misterX. Wenn nun die lokale Variable personen mit null initialisiert wird, entfernt der Garbage Collector nur das Array, nicht aber die Personen Margit und Hans, da es noch eine Referenz misterX auf die Person Margit gibt.

In der Praxis sind dies oft nicht mehr benötigte oder vergessene Referenzen, so dass die Garbage Collection diese Objekte im Speicher belässt. Man spricht hier von Memory Leaks oder Speicherlecks. Dies könnte man hier durch Dereferenzieren der lokalen Variablen misterX leicht verhindern.

public static void main(String[] args) {

  Person [ ] personen = { new Person("Margit") , new Person("Hans") };

  personen[0].setPartner( personen[1] );

  personen[1].setPartner( personen[0] );

            

  Person misterX = personen[ 0 ].getPartner( );

            

  personen = null;

}

Bevor der Garbage Collector ein Objekt aus dem Speicher entfernt, wird immer noch die Methode finalize( ) durchlaufen. Diese ist in der Klasse Object implementiert und kann überschrieben werden. Da der Entwickler aber weder weiß wann die Garbage Collection läuft, noch ob sie überhaupt läuft, ist diese Methode mit Vorsicht zu genießen. Seit JAVA 9 ist sie deprecated gekennzeichnet, weil viele Programmierer sie fehlerhaft eingesetzt haben.

Zusammenfassung

Dies war eine kurze einfache Darstellung der Garbage Collection. Alle nicht mehr erreichbaren Objekte ausgehend von der Root-Klasse und der main werden automatisch in parallelen Threads aus dem Heap-Speicher entfernt. Der Zeitpunkt ist für uns Entwickler nicht vorhersehbar.

In unserem Seminar Java Erweiterungen II (03323) wird das Thema mit schwachen (Weak Reference) und starken Referenzen vertieft.

 

Seminar zum Thema

 

Bildnachweis: Photo by Melodi2 at Morguefile.com