Gids voor WeakHashMap in Java

1. Overzicht

In dit artikel zullen we kijken naar een WeakHashMap van de java.util pakket.

Om de datastructuur te begrijpen, gebruiken we deze hier om een ​​eenvoudige cache-implementatie uit te rollen. Houd er echter rekening mee dat dit bedoeld is om te begrijpen hoe de kaart werkt, en het maken van uw eigen cache-implementatie is bijna altijd een slecht idee.

Simpel gezegd, de WeakHashMap is een hashtabel-gebaseerde implementatie van de Kaart interface, met sleutels van een Zwakke referentie type.

Een vermelding in een WeakHashMap wordt automatisch verwijderd wanneer de sleutel niet langer in normaal gebruik is, wat betekent dat er geen enkele is Referentie dat punt naar die sleutel. Wanneer het garbage collection (GC) -proces een sleutel weggooit, wordt de invoer ervan effectief van de kaart verwijderd, dus deze klasse gedraagt ​​zich enigszins anders dan andere Kaart implementaties.

2. Sterke, zachte en zwakke referenties

Om te begrijpen hoe de WeakHashMap werken, we moeten kijken naar een Zwakke referentie klasse - wat de basisconstructie is voor sleutels in de WeakHashMap implementatie. In Java hebben we drie hoofdtypen verwijzingen, die we in de volgende secties zullen uitleggen.

2.1. Sterke referenties

De sterke referentie is het meest voorkomende type Referentie die we gebruiken in onze dagelijkse programmering:

Integer prime = 1;

De variabele prime heeft een sterke referentie aan een Geheel getal object met waarde 1. Elk object met een sterke referentie die ernaar verwijst, komt niet in aanmerking voor GC.

2.2. Zachte verwijzingen

Simpel gezegd, een object met een SoftReference erop wijzen zal geen garbagecollection zijn totdat de JVM absoluut geheugen nodig heeft.

Laten we eens kijken hoe we een SoftReference in Java:

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

De prime object heeft een sterke referentie die ernaar verwijst.

Vervolgens zijn we aan het inpakken prime sterke verwijzing naar een zachte verwijzing. Na het maken van die sterke referentie nul, een prime object komt in aanmerking voor GC, maar wordt alleen verzameld als JVM absoluut geheugen nodig heeft.

2.3. Zwakke referenties

De objecten waarnaar alleen door zwakke verwijzingen wordt verwezen, worden gretig verzameld; de GC wacht in dat geval niet tot het geheugen nodig heeft.

We kunnen een Zwakke referentie in Java op de volgende manier:

Integer prime = 1; WeakReference zacht = nieuwe WeakReference (prime); prime = null;

Toen we een prime referentie nul, de prime object wordt garbage verzameld in de volgende GC-cyclus, omdat er geen andere sterke verwijzing naar is.

Referenties van een Zwakke referentie type worden gebruikt als sleutels in WeakHashMap.

3. WeakHashMap als een efficiënte geheugencache

Laten we zeggen dat we een cache willen bouwen die grote afbeeldingsobjecten als waarden en afbeeldingsnamen als sleutels bewaart. We willen een goede kaartimplementatie kiezen om dat probleem op te lossen.

Met behulp van een simpele Hash kaart zal geen goede keuze zijn omdat de waarde-objecten veel geheugen kunnen innemen. Bovendien worden ze nooit door een GC-proces uit de cache teruggewonnen, zelfs niet als ze niet meer in onze applicatie worden gebruikt.

Idealiter willen we een Kaart implementatie waarmee GC automatisch ongebruikte objecten kan verwijderen. Wanneer een sleutel van een groot afbeeldingsobject nergens in onze applicatie wordt gebruikt, wordt dat item uit het geheugen verwijderd.

Gelukkig is de WeakHashMap heeft precies deze kenmerken. Laten we onze WeakHashMap en kijk hoe het zich gedraagt:

WeakHashMap map = nieuwe WeakHashMap (); BigImage bigImage = nieuwe BigImage ("image_id"); UniqueImageName imageName = nieuwe 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);

We maken een WeakHashMap instantie die onze BigImage voorwerpen. We plaatsen een BigImage object als waarde en een imageName objectreferentie als sleutel. De imageName wordt op een kaart opgeslagen als een Zwakke referentie type.

Vervolgens stellen we de imageName verwijzing te zijn nul, daarom zijn er geen verwijzingen meer naar de bigImage voorwerp. Het standaardgedrag van een WeakHashMap is om een ​​item terug te vorderen dat er geen verwijzing naar heeft op de volgende GC, dus dit item zal uit het geheugen worden verwijderd door het volgende GC-proces.

We bellen een Systeem.gc () om de JVM te dwingen een GC-proces te starten. Na de GC-cyclus, onze WeakHashMap zal leeg zijn:

WeakHashMap map = nieuwe WeakHashMap (); BigImage bigImageFirst = nieuwe BigImage ("foo"); UniqueImageName imageNameFirst = nieuwe UniqueImageName ("name_of_big_image"); BigImage bigImageSecond = nieuwe BigImage ("foo_2"); UniqueImageName imageNameSecond = nieuwe 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));

Merk op dat alleen de imageNameFirst referentie is ingesteld op nul. De imageNameSecond referentie blijft ongewijzigd. Nadat GC is geactiveerd, bevat de kaart slechts één item - imageNameSecond.

4. Conclusie

In dit artikel hebben we gekeken naar soorten verwijzingen in Java om volledig te begrijpen hoe java.util.WeakHashMap werken. We hebben een eenvoudige cache gemaakt die gebruikmaakt van het gedrag van een WeakHashMap en test of het werkt zoals we hadden verwacht.

De implementatie van al deze voorbeelden en codefragmenten is te vinden in het GitHub-project - wat een Maven-project is, dus het moet gemakkelijk te importeren en uit te voeren zijn zoals het is.