Was ist der Unterschied zwischen java.lang.ref.WeakReference
y java.lang.ref.SoftReference
?
Antworten
Zu viele Anzeigen?SoftReference
ist für Caches konzipiert. Wenn festgestellt wird, dass ein WeakReference
auf ein sonst nicht erreichbares Objekt verweist, wird es sofort gelöscht. SoftReference
können so belassen werden, wie sie sind. Normalerweise gibt es einen Algorithmus, der sich auf die Menge des freien Speichers und die zuletzt genutzte Zeit bezieht, um zu bestimmen, ob er gelöscht werden sollte. Der derzeitige Algorithmus von Sun löscht den Verweis, wenn er in so vielen Sekunden nicht verwendet wurde, wie Megabytes an freiem Speicher auf dem Java-Heap vorhanden sind (konfigurierbar, Server-HotSpot prüft gegen den maximal möglichen Heap, der durch -Xmx
). SoftReference
s werden gelöscht, bevor OutOfMemoryError
wird ausgelöst, sofern er nicht anderweitig erreichbar ist.
Este Artikel kann sehr hilfreich sein, um starke, weiche, schwache und Phantomreferenzen zu verstehen.
Um Ihnen einen Überblick zu geben,
Wenn Sie nur über schwache Referenzen auf ein Objekt (ohne starke Referenzen), dann wird das Objekt von GC im nächsten GC-Zyklus zurückgewonnen.
Wenn Sie nur über weiche Referenzen zu einem Objekt (ohne starke Referenzen), dann wird das Objekt von GC nur dann zurückgefordert, wenn der JVM der Speicher ausgeht.
Man kann also sagen, dass starke Referenzen haben ultimative Kraft (kann niemals von GC eingezogen werden)
Weiche Referenzen sind leistungsstarke als schwache Referenzen (da sie dem GC-Zyklus entgehen können, bis der JVM der Speicher ausgeht)
Schwache Referenzen sind noch weniger leistungsfähig als Soft-Referenzen (da sie keinem GC-Zyklus entgehen können und zurückverlangt werden, wenn das Objekt keine andere starke Referenz hat).
Restaurant-Analogie
- Kellner - GC
- Du - Objekt im Heap
- Restaurantbereich/Raum - Haufenplatz
- Neuer Kunde - Neues Objekt, das einen Tisch im Restaurant wünscht
Wenn Sie nun ein starker Kunde (analog zur starken Referenz), dann werden Sie Ihren Tisch (den Speicherbereich auf dem Heap) auch dann nicht verlassen, wenn ein neuer Kunde ins Restaurant kommt oder was auch immer passiert. Der Kellner hat kein Recht, Ihnen zu sagen (oder Sie gar aufzufordern), das Restaurant zu verlassen.
Wenn Sie ein weicher Kunde (Wenn ein neuer Gast in das Restaurant kommt, wird der Kellner Sie nicht auffordern, den Tisch zu verlassen, es sei denn, es gibt keinen anderen freien Tisch, der den neuen Gast aufnehmen könnte. (Mit anderen Worten: Der Kellner bittet Sie nur dann, den Tisch zu verlassen, wenn ein neuer Kunde hereinkommt und kein anderer Tisch für diesen neuen Kunden frei ist)
Wenn Sie ein schwacher Kunde (analog zur schwachen Referenz), dann kann der Kellner Sie nach Belieben (zu jedem Zeitpunkt) auffordern, das Restaurant zu verlassen :P
Die sechs Arten von Objekt-Erreichbarkeitszuständen in Java:
- Stark ly erreichbare Objekte - GC wird nicht sammeln ( den Speicherplatz zurückfordern, der von ) diese Art von Objekt. Diese sind über einen Wurzelknoten oder ein anderes stark erreichbares Objekt erreichbar sein (d. h. über lokale Variablen, Klassenvariablen, Instanzvariablen usw.)
- Weich ly erreichbare Objekte - GC kann versuchen um diese Art von Objekten je nach Speicherkonkurrenz zu sammeln. Diese sind von der Root über eine oder mehrere weiche Referenzobjekte
- Schwach ly erreichbare Objekte - GC muss diese Art von Objekten zu sammeln. Diese sind von der Wurzel aus über eine oder mehrere schwache Referenzobjekte
- Wiederbelebbar Objekte - GC ist bereits dabei, diese Objekte zu sammeln. Aber sie können zu einem der Zustände - stark/weich/schwach - zurückkehren durch die Ausführung eines Finalizers
- Phantom ly erreichbares Objekt - GC bereits dabei ist, diese Objekte zu sammeln, und festgestellt hat, dass sie von keinem Finalizer wiederbelebt werden können (wenn sie selbst eine finalize()-Methode deklariert, wurde ihr Finalizer ausgeführt) . Diese sind von der Root über eine oder mehrere Phantom-Referenzobjekte
- Unerreichbar Objekt - Ein Objekt ist weder stark, weich, schwach noch als Phantom erreichbar und kann nicht wiederbelebt werden. Diese Objekte sind zur Wiedererlangung bereit
Für weitere Informationen: https://www.artima.com/insidejvm/ed2/gc16.html "Zusammenbruch
Der einzige wirkliche Unterschied
Per der Arzt , lose WeakReferences muss durch einen laufenden GC gelöscht werden.
Per der Arzt , lose SoftReferences muss gelöscht werden, bevor OOM ausgelöst wird.
Das ist der einzige wirkliche Unterschied. Alles andere ist nicht Teil des Vertrags. (Ich gehe davon aus, dass die neuesten Dokumente vertraglich sind).
SoftReferences sind nützlich. Speicherempfindliche Caches verwenden SoftReferences, nicht WeakReferences.
Die einzige richtig WeakReference wird verwendet, um den GC-Lauf zu beobachten. Sie tun dies, indem Sie eine neue WeakReference erstellen, deren Objekt sofort aus dem Geltungsbereich verschwindet, und dann versuchen, null aus weak_ref.get()
. Wenn es null
erfahren Sie, dass zwischen dieser Dauer der GC lief.
In Bezug auf falsch Verwendung von WeakReference, die Liste ist endlos:
-
ein lausiger Hack, um die Priorität-2-Softreferenz so zu implementieren, dass man sie nicht schreiben muss, dennoch funktioniert es nicht wie erwartet, da der Cache bei chaque GC-Lauf, auch wenn freier Speicher vorhanden ist. Siehe https://stackoverflow.com/a/3243242/632951 für Phails. (Außerdem, was ist, wenn Sie mehr als 2 Stufen der Cache-Priorität benötigen? Dann bräuchte man immer noch eine richtige Bibliothek dafür.)
-
ein lausiger Hack, um Daten mit einem Objekt einer bestehenden Klasse zu verknüpfen, dennoch es entsteht ein Speicherleck (OutOfMemoryError), wenn Ihr GC beschließt, eine Pause zu machen, nachdem Ihre weakreferences erstellt wurden. Außerdem ist es mehr als hässlich: Ein besserer Ansatz ist die Verwendung von Tupeln.
-
ein lausiger Hack, um Daten mit einem Objekt einer bestehenden Klasse zu verknüpfen, wobei die Klasse die Frechheit besitzt, sich selbst als nicht unterklassig zu kennzeichnen, und in einem bestehender Funktionscode die Sie aufrufen müssen. In einem solchen Fall besteht die richtige Lösung darin, entweder die Klasse zu bearbeiten und sie unterklassifizierbar zu machen, oder die Funktion zu bearbeiten und ihr eine Schnittstelle statt einer Klasse zuzuweisen, oder eine alternative Funktion zu verwenden.
Um den Speicherverbrauch in der Praxis zu untersuchen, habe ich ein Experiment mit Strong, Soft, Weak und Phantom-Referenzen unter hoher Last mit schweren Objekten durchgeführt, indem ich sie bis zum Ende des Programms beibehalten habe. Dann Überwachung der Heap-Nutzung und des GC-Verhaltens . Diese Metriken können von Fall zu Fall variieren, vermitteln aber sicherlich ein umfassendes Verständnis. Nachstehend sind die Ergebnisse aufgeführt.
Heap- und GC-Verhalten bei hoher Last
- Starke/Harte Referenz - Als das Programm fortgesetzt wurde, konnte die JVM das beibehaltene stark referenzierte Objekt nicht sammeln. Schließlich endete es in "java.lang.OutOfMemoryError: Java heap space"
- Weiche Referenz - Im weiteren Verlauf des Programms nahm die Heap-Nutzung weiter zu, aber OLD gen GC geschah, als es sich dem maximalen Heap näherte. GC begann etwas später nach dem Start des Programms.
- Schwache Referenz - Als das Programm begann, wurden die Objekte fast sofort fertiggestellt und eingesammelt. Die meisten Objekte wurden in der Young Generation Garbage Collection gesammelt.
- Phantom-Referenz - Ähnlich wie bei der schwachen Referenz wurden auch phantomreferenzierte Objekte sofort finalisiert und Garbage Collected. Es gab keine alte Generation GC & alle Objekte wurden in jungen Generation Garbage Collection selbst gesammelt.
Sie können mehr erfahren Diagramme, Statistiken und Beobachtungen zu diesem Experiment hier .