Qual è la differenza tra java.lang.ref.WeakReference
e java.lang.ref.SoftReference
?
Qual è la differenza tra java.lang.ref.WeakReference
e java.lang.ref.SoftReference
?
Risposte:
Da capire i riferimenti deboli , di Ethan Nicholas:
Riferimenti deboli
Un riferimento debole , in poche parole, è un riferimento che non è abbastanza forte da forzare un oggetto a rimanere in memoria. I riferimenti deboli ti consentono di sfruttare la capacità del garbage collector di determinare la raggiungibilità per te, quindi non devi farlo da solo. Si crea un riferimento debole come questo:
WeakReference weakWidget = new WeakReference(widget);
e poi altrove nel codice è possibile utilizzare
weakWidget.get()
per ottenere l'Widget
oggetto reale . Naturalmente il riferimento debole non è abbastanza forte da impedire la garbage collection, quindi potresti trovare (se non ci sono riferimenti forti al widget) cheweakWidget.get()
improvvisamente inizia a tornarenull
....
Riferimenti morbidi
Un riferimento morbido è esattamente come un riferimento debole, tranne per il fatto che è meno desideroso di gettare via l'oggetto a cui si riferisce. Un oggetto che è solo debolmente raggiungibile (i riferimenti più forti ad esso sono
WeakReferences
) verrà scartato al successivo ciclo di raccolta dei rifiuti, ma un oggetto che è delicatamente raggiungibile si bloccherà generalmente per un po '.
SoftReferences
non sono tenuti a comportarsi diversamente daWeakReferences
, ma in pratica gli oggetti facilmente raggiungibili vengono generalmente mantenuti fintanto che la memoria è abbondante. Questo li rende un'ottima base per una cache, come la cache di immagini descritta sopra, poiché puoi lasciare che il garbage collector si preoccupi sia di quanto siano raggiungibili gli oggetti (un oggetto fortemente raggiungibile non verrà mai rimosso dalla cache) sia di quanto male ha bisogno della memoria che stanno consumando.
E Peter Kessler ha aggiunto in un commento:
Sun JRE tratta le SoftReferences in modo diverso dalle DeboleReferenze. Tentiamo di aggrapparci all'oggetto a cui fa riferimento un SoftReference se non c'è pressione sulla memoria disponibile. Un dettaglio: i criteri per i JRE "-client" e "-server" sono diversi: il JRE -client cerca di ridurre l'ingombro preferendo cancellare SoftReferences piuttosto che espandere l'heap, mentre il JRE -server cerca di mantenere il tuo prestazioni elevate preferendo espandere l'heap (se possibile) piuttosto che cancellare SoftReferences. Una taglia non va bene per tutti.
I riferimenti deboli vengono raccolti avidamente. Se GC rileva che un oggetto è debolmente raggiungibile (raggiungibile solo attraverso riferimenti deboli), cancella immediatamente i riferimenti deboli a quell'oggetto. Come tali, sono utili per mantenere un riferimento a un oggetto per il quale il tuo programma conserva anche (informazioni fortemente riferite) "informazioni associate", come informazioni di riflessione memorizzate nella cache su una classe o un wrapper per un oggetto, ecc. Tutto ciò che rende non ha senso mantenere l'oggetto a cui è associato è GC-ed. Quando il riferimento debole viene cancellato, viene accodato in una coda di riferimento che il codice esegue il polling da qualche parte e scarta anche gli oggetti associati. Cioè, si conservano ulteriori informazioni su un oggetto, ma tali informazioni non sono necessarie una volta che l'oggetto a cui si riferisce scompare. In realtà, in alcune situazioni è anche possibile sottoclassare WeakReference e conservare le informazioni aggiuntive associate sull'oggetto nei campi della sottoclasse WeakReference. Un altro uso tipico di WeakReference è in combinazione con Maps per mantenere le istanze canoniche.
Le SoftReferenze sono invece utili per la memorizzazione nella cache di risorse esterne e ricreabili poiché il GC in genere ritarda a cancellarle. È comunque garantito che tutte le SoftReferences verranno cancellate prima che venga lanciato OutOfMemoryError, quindi teoricamente non possono causare un OOME [*].
Un tipico esempio di caso d'uso consiste nel mantenere una forma analizzata di un contenuto da un file. Dovresti implementare un sistema in cui caricare un file, analizzarlo e mantenere un SoftReference sull'oggetto radice della rappresentazione analizzata. La prossima volta che avrai bisogno del file, proverai a recuperarlo tramite SoftReference. Se riesci a recuperarlo, ti sei risparmiato un altro carico / analisi e se il GC lo ha cancellato nel frattempo, lo ricarichi. In questo modo, utilizzi memoria libera per l'ottimizzazione delle prestazioni, ma non rischi un OOME.
Ora per il [*]. Mantenere un SoftReference non può causare un OOME in sé. Se d'altra parte si utilizza erroneamente SoftReference per un'attività che si intende utilizzare un WeakReference (vale a dire, mantenere le informazioni associate a un oggetto in qualche modo fortemente referenziate e scartarle quando l'oggetto di riferimento viene cancellato), è possibile eseguire OOME come il codice che esegue il polling di ReferenceQueue e scarta gli oggetti associati potrebbe non funzionare in modo tempestivo.
Quindi, la decisione dipende dall'uso - se stai memorizzando nella cache informazioni che sono costose da costruire, ma comunque ricostruibili da altri dati, usa riferimenti morbidi - se stai mantenendo un riferimento a un'istanza canonica di alcuni dati, o vuoi avere un riferimento a un oggetto senza "possederlo" (impedendogli così di essere GC'd), usare un riferimento debole.
WeakReference
è che nei luoghi in cui si dovrebbe usarlo, il fatto che si possa rimanere validi per un po 'di tempo dopo che il riferimento esce dal campo di applicazione può essere tollerabile, ma non è desiderabile.
WeakReference
quale è osservare le corse GC. Vedere elaborazione: stackoverflow.com/a/46291143/632951
In Java ; nell'ordine dal più forte al più debole, ci sono: Forte, Morbido, Debole e Fantasma
Un riferimento forte è un riferimento normale che protegge l'oggetto indicato dalla raccolta da parte di GC. cioè non si raccoglie mai la spazzatura.
Un riferimento Soft può essere raccolto dal Garbage Collector, ma probabilmente non verrà raccolto fino a quando non sarà necessaria la sua memoria. cioè la spazzatura si raccoglie prima OutOfMemoryError
.
Un riferimento debole è un riferimento che non protegge un oggetto referenziato dalla raccolta da parte di GC. cioè la spazzatura si raccoglie quando nessun riferimento forte o morbido.
Un riferimento Phantom è un riferimento a un oggetto a cui viene fatto un riferimento fantasma dopo che è stato finalizzato, ma prima che la sua memoria allocata sia stata recuperata.
Analogia: supponiamo che una JVM sia un regno, Object sia un re del regno e GC sia un attaccante del regno che cerca di uccidere il re (oggetto).
until memory is available
non ha senso. Intendi is eligible for collection by garbage collector, but probably won't be collected until its memory is needed for another use
?
Riferimento debole http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html
Principio: weak reference
è legato alla raccolta dei rifiuti. Normalmente, l'oggetto con uno o più reference
non sarà idoneo per la garbage collection.
Il principio di cui sopra non è applicabile quando lo è weak reference
. Se un oggetto ha solo un riferimento debole con altri oggetti, è pronto per la garbage collection.
Diamo un'occhiata all'esempio seguente: Abbiamo un oggetto Map
con cui Chiave fa riferimento a un oggetto.
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> aMap = new
HashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
System.out.println("Size of Map" + aMap.size());
}
}
Ora, durante l'esecuzione del programma, abbiamo realizzato emp = null
. Tenere Map
premuto il tasto non ha senso qui com'è null
. Nella situazione sopra, l'oggetto non viene raccolto.
WeakHashMap
WeakHashMap
è uno in cui le voci ( key-to-value mappings
) verranno rimosse quando non è più possibile recuperarle da Map
.
Consentitemi di mostrare lo stesso esempio sopra con WeakHashMap
import java.util.WeakHashMap;
public class Test {
public static void main(String args[]) {
WeakHashMap<Employee, EmployeeVal> aMap =
new WeakHashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
int count = 0;
while (0 != aMap.size()) {
++count;
System.gc();
}
System.out.println("Took " + count
+ " calls to System.gc() to result in weakHashMap size of : "
+ aMap.size());
}
}
Uscita: Ha preso 20 calls to System.gc()
a risultato aMap size
di: 0.
WeakHashMap
ha solo riferimenti deboli alle chiavi, non riferimenti forti come altre Map
classi. Ci sono situazioni che devi fare attenzione quando il valore o la chiave è fortemente referenziato anche se hai usato WeakHashMap
. Questo può essere evitato avvolgendo l'oggetto in un WeakReference .
import java.lang.ref.WeakReference;
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> map =
new HashMap<Employee, EmployeeVal>();
WeakReference<HashMap<Employee, EmployeeVal>> aMap =
new WeakReference<HashMap<Employee, EmployeeVal>>(
map);
map = null;
while (null != aMap.get()) {
aMap.get().put(new Employee("Vinoth"),
new EmployeeVal("Programmer"));
System.out.println("Size of aMap " + aMap.get().size());
System.gc();
}
System.out.println("Its garbage collected");
}
}
Riferimenti morbidi.
Soft Reference
è leggermente più forte di quel riferimento debole. Il riferimento software consente la raccolta dei rifiuti, ma chiede al garbage collector di cancellarlo solo se non ci sono altre opzioni.
Il garbage collector non raccoglie in modo aggressivo oggetti delicatamente raggiungibili come fa con quelli debolmente raggiungibili - invece raccoglie oggetti delicatamente raggiungibili solo se "ha bisogno" della memoria. I riferimenti morbidi sono un modo di dire al garbage collector, "Finché la memoria non è troppo stretta, mi piacerebbe tenere questo oggetto in giro. Ma se la memoria diventa davvero stretta, vai avanti e raccoglilo e mi occuperò con quello." Il garbage collector deve cancellare tutti i riferimenti software prima di poterlo lanciare OutOfMemoryError
.
NullPointerException
in aMap.get().put(...)
.
WeakHashMap
all'esempio (poiché quello è il primo che sta dimostrando un comportamento debole). Guarda il documento per "WeakHashMap": "An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. "
l'intero punto di usare WeakHashMap è che non devi dichiarare / passare un WeakReference; WeakHashMap lo fa per te, internamente. docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html
WeakHashMap
azione, con l'app di esempio che mostra come le voci vengono rimosse solo dopo l' esecuzione della garbage collection, vedere la mia risposta alla domanda, WeakHashMap è in continua crescita o cancella le chiavi della garbage? .
L'unica vera differenza tra un riferimento debole e un riferimento debole è quella
il garbage collector utilizza algoritmi per decidere se recuperare o meno un oggetto delicatamente raggiungibile, ma recupera sempre un oggetto debolmente raggiungibile.
SoftReference
è progettato per le cache. Quando viene rilevato che un WeakReference
riferimento a un oggetto altrimenti non raggiungibile, verrà cancellato immediatamente. SoftReference
può essere lasciato così com'è. In genere esiste un algoritmo relativo alla quantità di memoria libera e al tempo impiegato per determinare se deve essere cancellato. L'attuale algoritmo di Sun è quello di cancellare il riferimento se non è stato utilizzato in tanti secondi quanti sono i megabyte di memoria libera sull'heap Java (configurabile, l'HotSpot del server controlla rispetto all'heap massimo possibile impostato da -Xmx
). SoftReference
s verrà cancellato prima che OutOfMemoryError
venga lanciato, se non diversamente raggiungibile.
java.lang
. Un simile abuso di sinonimi non sta facendo nulla di buono.
Questo articolo può essere di grande aiuto per comprendere riferimenti forti, morbidi, deboli e fantasma.
Per darti un riepilogo,
Se hai solo riferimenti deboli a un oggetto (senza riferimenti forti), l'oggetto verrà recuperato da GC nel ciclo GC immediatamente successivo.
Se si dispone solo di riferimenti software a un oggetto (senza riferimenti forti), l'oggetto verrà recuperato da GC solo quando JVM esaurisce la memoria.
Quindi puoi dire che i riferimenti forti hanno il potere supremo (non possono mai essere raccolti da GC)
I riferimenti software sono potenti rispetto ai riferimenti deboli (poiché possono sfuggire al ciclo GC fino a quando la memoria JVM esaurisce la memoria)
I riferimenti deboli sono persino meno potenti dei riferimenti deboli (in quanto non possono sfuggire a nessun ciclo GC e verranno recuperati se l'oggetto non ha altri riferimenti forti).
Analogia del ristorante
Ora, se sei un cliente forte (analogo a un riferimento forte), anche se un nuovo cliente arriva nel ristorante o cosa succede, non lascerai mai il tuo tavolo (l'area della memoria nell'heap). Il cameriere non ha il diritto di dirti (o addirittura richiederti) di lasciare il ristorante.
Se sei un cliente soft (analogo al riferimento soft), quindi se un nuovo cliente arriva nel ristorante, il cameriere non ti chiederà di lasciare il tavolo a meno che non ci sia altro tavolo vuoto per accogliere il nuovo cliente. (In altre parole, il cameriere ti chiederà di lasciare il tavolo solo se entra un nuovo cliente e non è rimasto nessun altro tavolo per questo nuovo cliente)
Se sei un cliente debole (analogo al riferimento debole), il cameriere, a suo piacimento, può (in qualsiasi momento) chiederti di lasciare il ristorante: P
Come da documento , i riferimenti deboli allentati devono essere cancellati da un GC in esecuzione.
Come da documento , le SoftReferenze libere devono essere cancellate prima che venga lanciata OOM.
Questa è l'unica vera differenza. Tutto il resto non fa parte del contratto. (Presumo che gli ultimi documenti siano contrattuali.)
Le SoftReferences sono utili. Le cache sensibili alla memoria utilizzano SoftReferences, non WeakReferences.
weak_ref.get()
. Quando è null
, impari che tra questa durata, il GC ha funzionato.
Per quanto riguarda l' uso errato di WeakReference, l'elenco è infinito:
un trucco pessimo per implementare il softreference di priorità 2 in modo tale da non doverne scrivere uno, ma non funziona come previsto perché la cache verrebbe cancellata ad ogni esecuzione di GC, anche quando c'è memoria libera. Vedi https://stackoverflow.com/a/3243242/632951 per phails. (Inoltre, cosa succede se hai bisogno di più di 2 livelli di priorità della cache? Dovresti comunque avere bisogno di una vera libreria per questo.)
un trucco pessimo per associare i dati a un oggetto di una classe esistente, ma crea una perdita di memoria (OutOfMemoryError) quando il tuo GC decide di fare una pausa dopo la creazione dei tuoi riferimenti deboli. Inoltre, è al di là del brutto: un approccio migliore è usare le tuple.
un trucco scadente per associare i dati a un oggetto di una classe esistente, in cui la classe ha il coraggio di rendersi non classificabile e viene utilizzata in un codice di funzione esistente che è necessario chiamare. In tal caso, la soluzione corretta consiste nel modificare la classe e renderla sottoclassabile, oppure modificare la funzione e far sì che prenda un'interfaccia anziché una classe, oppure usi una funzione alternativa.
equals()
è solo l'identità dell'oggetto? I riferimenti morbidi sembrano uno spreco lì, perché una volta che un oggetto chiave non è più fortemente raggiungibile, nessuno potrà mai più cercare quella mappatura.
I sei tipi di stati di raggiungibilità degli oggetti in Java:
Per maggiori dettagli: https://www.artima.com/insidejvm/ed2/gc16.html «collapse
Bisogna essere consapevoli che un oggetto debolmente referenziato verrà raccolto solo quando ha SOLO riferimenti deboli. Se ha un riferimento forte, non viene raccolto, indipendentemente da quanti riferimenti deboli ha.
Per dare un aspetto all'utilizzo della memoria in azione, ho fatto un esperimento con riferimenti Strong, Soft, Weak & Phantom sotto carico pesante con oggetti pesanti, conservandoli fino alla fine del programma. Quindi monitorato l'utilizzo dell'heap e il comportamento GC . Queste metriche possono variare caso per caso, ma offrono sicuramente una comprensione di alto livello. Di seguito sono riportati i risultati.
Comportamento di heap e GC sotto carico pesante
Puoi ottenere grafici più approfonditi , statistiche, osservazioni per questo esperimento qui .
WeakReference : gli oggetti a cui viene fatto solo un riferimento debole vengono raccolti in ogni ciclo GC (minore o completo).
SoftReference : quando vengono raccolti oggetti a cui viene fatto solo un leggero riferimento dipende da:
-XX: SoftRefLRUPolicyMSPerMB = flag N (il valore predefinito è 1000, ovvero 1 secondo)
Quantità di memoria libera nell'heap.
Esempio:
Quindi l'oggetto a cui fa riferimento solo SoftReference verrà raccolto se l'ultima volta in cui è stato effettuato l'accesso è maggiore di 10 secondi.