Anleitung zu WeakHashMap in Java

1. Übersicht

In diesem Artikel sehen wir uns eine WeakHashMap aus dem Paket java.util an.

Um die Datenstruktur zu verstehen, verwenden wir sie hier, um eine einfache Cache-Implementierung einzuführen. Beachten Sie jedoch, dass dies dazu gedacht ist, die Funktionsweise der Karte zu verstehen, und dass das Erstellen einer eigenen Cache-Implementierung fast immer eine schlechte Idee ist.

Einfach ausgedrückt ist die WeakHashMap eine auf Hashtabellen basierende Implementierung der Map- Schnittstelle mit Schlüsseln vom Typ WeakReference .

Ein Eintrag in einer WeakHashMap wird automatisch entfernt, wenn sein Schlüssel nicht mehr normal verwendet wird. Dies bedeutet, dass es keine einzige Referenz gibt , die auf diesen Schlüssel verweist . Wenn der Garbage Collection (GC) -Prozess einen Schlüssel verwirft, wird sein Eintrag effektiv aus der Map entfernt, sodass sich diese Klasse etwas anders verhält als andere Map- Implementierungen.

2. Starke, weiche und schwache Referenzen

Um zu verstehen, wie die WeakHashMap funktioniert, müssen wir uns eine WeakReference- Klasse ansehen - das grundlegende Konstrukt für Schlüssel in der WeakHashMap- Implementierung. In Java gibt es drei Haupttypen von Referenzen, die in den folgenden Abschnitten erläutert werden.

2.1. Starke Referenzen

Die starke Referenz ist die häufigste Referenzart , die wir in unserer täglichen Programmierung verwenden:

Integer prime = 1;

Die Variable prime hat eine starke Referenz auf ein Integer- Objekt mit dem Wert 1. Jedes Objekt, auf das eine starke Referenz verweist, ist nicht für die GC geeignet.

2.2. Weiche Referenzen

Einfach ausgedrückt, ein Objekt, auf das eine SoftReference verweist, wird erst dann mit Müll gesammelt, wenn die JVM unbedingt Speicher benötigt.

Mal sehen, wie wir eine SoftReference in Java erstellen können :

Integer prime = 1; SoftReference soft = new SoftReference(prime); prime = null;

Das Prime - Objekt hat einen starken Bezug auf sie zeigt.

Als nächstes wir Einwickeln prime starke Referenz in eine weiche Referenz. Dass starke Referenz Nachdem null , ein Prime - Objekt ist für GC berechtigt aber nur dann erhoben, wenn JVM absolut Speicher benötigt.

2.3. Schwache Referenzen

Die Objekte, auf die nur durch schwache Referenzen verwiesen wird, sind eifrig gesammelter Müll; Der GC wartet in diesem Fall nicht, bis er Speicher benötigt.

Wir können eine WeakReference in Java folgendermaßen erstellen :

Integer prime = 1; WeakReference soft = new WeakReference(prime); prime = null;

Wenn wir einen gemacht prime Referenz null , die prime wird Objekt Müll in dem nächsten GC - Zyklus gesammelt werden, da es keine andere starke Bezugnahme auf mich zeigen ist.

Referenzen eines WeakReference- Typs werden als Schlüssel in WeakHashMap verwendet .

3. WeakHashMap als effizienter Speichercache

Angenommen, wir möchten einen Cache erstellen, der große Bildobjekte als Werte und Bildnamen als Schlüssel enthält. Wir möchten eine geeignete Kartenimplementierung auswählen, um dieses Problem zu lösen.

Die Verwendung einer einfachen HashMap ist keine gute Wahl, da die Wertobjekte möglicherweise viel Speicher belegen. Darüber hinaus werden sie von einem GC-Prozess niemals aus dem Cache zurückgefordert, selbst wenn sie in unserer Anwendung nicht mehr verwendet werden.

Idealerweise möchten wir eine Map- Implementierung, mit der GC nicht verwendete Objekte automatisch löschen kann. Wenn ein Schlüssel eines großen Bildobjekts in unserer Anwendung an keiner Stelle verwendet wird, wird dieser Eintrag aus dem Speicher gelöscht.

Glücklicherweise hat die WeakHashMap genau diese Eigenschaften. Lassen Sie uns unsere WeakHashMap testen und sehen, wie sie sich verhält:

WeakHashMap map = new WeakHashMap(); BigImage bigImage = new BigImage("image_id"); UniqueImageName imageName = new UniqueImageName("name_of_big_image"); map.put(imageName, bigImage); assertTrue(map.containsKey(imageName)); imageName = null; System.gc(); await().atMost(10, TimeUnit.SECONDS).until(map::isEmpty);

Wir erstellen eine WeakHashMap- Instanz, in der unsere BigImage- Objekte gespeichert werden. Wir setzen ein BigImage- Objekt als Wert und eine imageName- Objektreferenz als Schlüssel. Der Bildname wird in einer Karte als WeakReference- Typ gespeichert .

Als Nächstes setzen wir die imageName- Referenz auf null , daher gibt es keine weiteren Referenzen, die auf das bigImage- Objekt verweisen . Das Standardverhalten einer WeakHashMap besteht darin, einen Eintrag zurückzugewinnen, auf den beim nächsten GC kein Verweis verweist, sodass dieser Eintrag beim nächsten GC-Prozess aus dem Speicher gelöscht wird.

Wir rufen ein System.gc () auf, um die JVM zu zwingen, einen GC-Prozess auszulösen. Nach dem GC-Zyklus ist unsere WeakHashMap leer:

WeakHashMap map = new WeakHashMap(); BigImage bigImageFirst = new BigImage("foo"); UniqueImageName imageNameFirst = new UniqueImageName("name_of_big_image"); BigImage bigImageSecond = new BigImage("foo_2"); UniqueImageName imageNameSecond = new UniqueImageName("name_of_big_image_2"); map.put(imageNameFirst, bigImageFirst); map.put(imageNameSecond, bigImageSecond); assertTrue(map.containsKey(imageNameFirst)); assertTrue(map.containsKey(imageNameSecond)); imageNameFirst = null; System.gc(); await().atMost(10, TimeUnit.SECONDS) .until(() -> map.size() == 1); await().atMost(10, TimeUnit.SECONDS) .until(() -> map.containsKey(imageNameSecond));

Beachten Sie, dass nur die Referenz imageNameFirst auf null gesetzt ist . Die imageNameSecond- Referenz bleibt unverändert. Nach dem Auslösen des GC enthält die Karte nur einen Eintrag - imageNameSecond .

4. Fazit

In diesem Artikel haben wir uns Referenztypen in Java angesehen, um zu verstehen, wie java.util funktioniert . WeakHashMap funktioniert. Wir haben einen einfachen Cache erstellt, der das Verhalten einer WeakHashMap nutzt und testet , ob es wie erwartet funktioniert.

Die Implementierung all dieser Beispiele und Codefragmente finden Sie im GitHub-Projekt - einem Maven-Projekt. Daher sollte es einfach zu importieren und auszuführen sein.