© DrHitch/Shutterstock.com
Memory Leaks Tools

3 Effective Java: WeakReferences - Memory Leaks vorbeugen


Die vorangegangenen Kapitel gingen der Frage nach, wie Memory Leaks entstehen ([1] bis [3]) und mit welchen Techniken und Tools man nach ihnen suchen kann ([4] und [5]). Dieses Mal wollen wir uns WeakReferences genauer ansehen. Mit ihrer Hilfe ist es möglich, Situationen zu vermeiden, in denen Memory Leaks entstehen können.

Gehen wir noch einmal zurück zu dem Beispiel eines Memory Leaks, das wir ausführlich im ersten Kapitel des shortcuts zum Thema Memory Leaks diskutiert haben [1]. In dem Beispiel haben wir einen rudimentären Server auf Basis der mit Java 7 eingeführten AsynchronousSocketChannels implementiert. Das Memory Leak entstand dadurch, dass wir im Server für jeden neuen Client Verwaltungsinformationen in einer Map gespeichert und diese clientspezifischen Map-Einträge nicht nach der Beendigung der Kommunikation mit den jeweiligen Clients wieder gelöscht haben. Es ist offensichtlich, dass sich die Map mit jedem neuen Client vergrößert. Erzeugt man also in einem Testprogramm viele Clients hintereinander, so stürzt der Server irgendwann mit einem OutOfMemoryError ab. Der Sourcecode zu dem Beispiel sowie verschiedene alternative Korrekturen finden sich unter [6].

Wie wir in dem folgenden Kapitel [2] diskutiert haben, ist diese Situation relativ typisch für ein Memory Leak, das zu einem OutOfMemoryError führt. Es gibt in Java häufig Verwaltungen, in die man Objekte eintragen und aus denen man letztere, wenn sie nicht mehr benötigt werden, auch wieder löschen muss. Ein weiteres Beispiel, das wir uns dazu angesehen haben, ist die Verwaltung der Callbacks, die man als AWT Event Listener einhängt.

Bisher sind wir so verblieben, dass es Aufgabe des Benutzers ist, solche Verwaltungen korrekt zu verwenden. Das heißt, er muss darauf achten, dass er jedes Objekt, das er in eine solche Verwaltung eingetragen hat, auch zum angemessenen Zeitpunkt wieder löscht. Wenn er sich nicht daran hält, hat er als Konsequenz das entstandene Memory Leak und den eventuell folgenden Programmabsturz aufgrund eines OutOfMemoryError zu verantworten.

Ungewollte Referenzen und WeakReferences

In diesem Kapitel wollen wir nun sehen, ob derjenige, der die Verwaltung implementiert und bereitstellt, nicht auch etwas tun kann, was dazu führt, dass es erst gar nicht zu Memory Leaks kommen kann. Schön wäre es doch, wenn der Benutzer sich gar nicht um das Löschen kümmern müsste, weil dies automatisch erledigt wird.

Um zu verstehen, wie so etwas gehen könnte, rufen wir uns noch einmal in Erinnerung, wie es genau zu einem Memory Leak kommt. Der Garbage Collector ermittelt ausgehend von so genannten Root References, welche Objekte in einem Java-Programm referenziert und damit erreichbar sind. Alle nicht erreichbaren Objekte räumt der Garbage Collector bei der Garbage Collection weg und gibt ihren Speicher frei. Wenn wir nun auf ein Objekt verweisen, von dem wir sicher sagen können, dass wir es im weiteren Kontext unseres Programms gar nicht mehr benutzen werden, haben wir ein Memory Leak, denn das nicht mehr benötigte Objekt wird vom Garbage Collector nicht weggeräumt, weil es noch referenziert wird. Diese Referenz wird in der englischsprachigen Fachliteratur unwanted reference (also: ungewollte Referenz) genannt.

Übertragen wir diese Beschreibung auf das Memory-Leaks-Beispiel aus dem ersten Kapitel des diesem vorausgehenden shortcuts: Die clientspezifischen Verwaltungsdaten werden auch nach der Beendigung der Kommunikation mit dem Client weiter über die Map referenziert, sodass der Garbage Collector sie nicht freigeben kann. Die Map mit ihrer internen Datenstruktur bildet also unsere ungewollte Referenz auf die clientspezifischen Daten.

Wie wäre es denn nun, wenn man dem Garbage Collector explizit sagen könnte, dass die ungewollten Referenzen genau das sind: ungewollt. Man möchte ausdrücken, dass diese Referenzen zwar für die Navigation im Objektgraphen der Applikation zur Verfügung stehen, damit man die Objekte erreichen kann. Aber für den Garbage Collector soll es nicht bedeuten, dass die Objekte, auf die sie verweisen, am Leben gehalten werden sollen. Genau zu diesem Zweck gibt es seit dem JDK 1.2 das Package java.lang.ref im JDK, mit dem neben einigen weiteren Referenztypen (siehe Kasten „Referenztypen im JDK“) die so genannten WeakReferences eingeführt wurden.

Die Idee ist, dass man ungewollte Referenzen innerhalb einer Datenverwaltung als WeakReferences implementiert. Damit braucht sich der Benutzer der Datenverwaltung nicht mehr um das Löschen der Objekte, die er in die Datenverwaltung eingetragen hat, zu kümmern. Das Löschen wird stattdessen automatisch vom Garbage Collector erledigt. Wie das Ganze im Detail geht, wollen wir weiter unten am Beispiel des Servers aus dem ersten Kapitel des diesem vorausgegangenen shortcuts [1] diskutieren. Als Erstes sehen wir uns aber die WeakReference selbst etwas genauer an.

Die WeakReference im Detail

Fangen wir zuerst mit der Namensgebung an. Da man auf ein Objekt über eine normale Referenz und über eine WeakReference verweisen kann, reicht ein Verb wie „referenzieren“ nicht mehr aus, um die spezifische Art der Referenz zu beschreiben. In der englischen Fachliteratur haben sich deshalb die Ausdrücke strongly referenced für das Referenzieren über eine normale Referenz und weakly referenced für das Referenzieren über eine WeakReference gebildet. In Anlehnung daran werden wir die Ausdrücke strong-referenziert bzw. weak-referenziert verwenden. Entsprechend ergibt sich: Ein Objekt, das strong-erreichbar (also über normale Referenzen erreichbar) ist, wird nich...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang