Schwache Referenzen und Cleaner

Die Referenzen auf Objekte, die wir im Alltag um uns herum haben, heißen starke Referenzen, weil die automatische Speicherbereinigung niemals ein benutztes Objekt freigeben würde. Neben den starken Referenzen gibt es jedoch auch schwache Referenzen, die es dem GC erlaubt, die Objekte zu entfernen. Was erst einmal verrückt klingt wird dann interessant, wenn es um die Implementierung von Caching-Datenstrukturen geht; ist das Objekt im Cache, ist das schön und der Zugriff schnell – ist das Objekt nicht im Cache, dann ist das auch in Ordnung, und der Zugriff dauert etwas länger. Wir können schwache Referenzen also gut verwenden, um im Cache liegende Objekte aufzubauen, die die automatische Speicherbereinigung wegräumen darf, wenn es im Speicher knapp wird.

Schwache Referenzen interagieren also in einer einfachen Weise mit der automatischen Speicherbereinigung und dafür gibt es im java.base-Modul im Paket java.lang.ref ein paar Typen. Am Wichtigsten sind die Behälter (engl. reference object gennant), die wie ein Optional ein Objekt referenzieren, das aber plötzlich verschwunden sein kann:

  • SoftReference<T>. Ein Behälter für softly reachable Objekte. Die Objekte werden vom GC spät freigegeben, wenn es kurz vor einem OutOutMemoryError
  • WeakReference<T>. Ein Behälter für weakly reachable Objekte. Die Objekte werden vom GC schon relativ früh beim ersten GC freigegeben.
  • PhantomReference<T>. Ein Behälter, der immer leer ist, aber dazu dient mitzubekommen, wenn der GC sich von einem Objekt trennt.
  • Reference<T>. Abstakte Basisklasse von PhantomReference, SoftReference, WeakReference.

Die Behälter selbst werden vom GC nicht entfernt, sodass eine ReferenceQueue<T> ein Abfragen erlaubt, um festzustellen, welche Reference-Behälter leer sind und z. B. aus einer Datenstruktur entfernt werden können – leere Behälter sind nutzlos und können nicht wieder recycelt werden.

Ein neuer Typ ab Java 9 im Paket ist Cleaner, der eine Alternative zur Finalizierung ist. Beim Cleaner lässt sich eine Operation (vom Typ Cleaner.Cleanable) anmelden, die immer dann aufgerufen wird, wenn die automatische Speicherbereinigung zuschlägt und das Objekt nicht mehr erreichbar ist. Intern greift die Klasse auf PhantomReference zurück.

Beispiel: Lege einen Punkt an, registriere einen Cleaner und rege danach den GC an. Eine Konsolenausgabe „Punkt ist weg!“ ist wahrscheinlich:

Point p = new Point( 1, 2 );

Cleaner.create().register( p, () -> System.out.println( "Punkt ist weg!" ) );

p = null;

byte[] bytes = new byte[ (int) Runtime.getRuntime().freeMemory() ];

Auf keinen Fall darf die Aufräumoperation p wieder referenzieren.

 

Über Christian Ullenboom

Ich bin Christian Ullenboom und Autor der Bücher ›Java ist auch eine Insel. Einführung, Ausbildung, Praxis‹ und ›Java SE 8 Standard-Bibliothek. Das Handbuch für Java-Entwickler‹. Seit 1997 berate ich Unternehmen im Einsatz von Java. Sun ernannte mich 2005 zum ›Java-Champion‹.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.