Ho letto questo articolo sull'argomento, ma non lo capisco davvero. Per favore, dammi qualche consiglio insieme ad esempi quando descrivo i concetti.
Ho letto questo articolo sull'argomento, ma non lo capisco davvero. Per favore, dammi qualche consiglio insieme ad esempi quando descrivo i concetti.
Risposte:
Java fornisce due diversi tipi / classi di oggetti di riferimento : forte e debole . Gli oggetti di riferimento deboli possono essere ulteriormente divisi in morbido e fantasma .
Andiamo punto per punto.
Oggetto di riferimento forte
StringBuilder builder = new StringBuilder();
Questo è il tipo / classe predefinito dell'oggetto di riferimento, se non diversamente specificato: builder
è un forte oggetto di riferimento. Questo tipo di riferimento rende l'oggetto referenziato non idoneo per GC. Cioè, ogni volta che un oggetto viene referenziato da una catena di oggetti di riferimento forti , non può essere spazzato via.
Oggetto di riferimento debole
WeakReference<StringBuilder> weakBuilder = new WeakReference<StringBuilder>(builder);
Gli oggetti di riferimento deboli non sono il tipo / classe di default dell'oggetto di riferimento e per essere utilizzati devono essere esplicitamente specificati come nell'esempio sopra. Questo tipo di riferimento rende l'oggetto di riferimento idoneo per GC. Vale a dire, nel caso in cui l'unico riferimento raggiungibile per l' StringBuilder
oggetto in memoria sia, in realtà, il riferimento debole, quindi al GC è consentito eseguire il garbage collection StringBuilder
dell'oggetto. Quando un oggetto in memoria è raggiungibile solo da oggetti di riferimento deboli, diventa automaticamente idoneo per GC.
Livelli di debolezza
Possono essere arruolati due diversi livelli di debolezza: morbido e fantasma .
Un oggetto di riferimento morbido è fondamentalmente un oggetto di riferimento debole che rimane un po 'più in memoria: normalmente, resiste al ciclo GC fino a quando non è disponibile memoria e non vi è il rischio OutOfMemoryError
(in tal caso, può essere rimosso).
D'altra parte, un oggetto di riferimento fantasma è utile solo per sapere esattamente quando un oggetto è stato effettivamente rimosso dalla memoria: normalmente sono usati per correggere comportamenti di revival / resurrezione finalize () strani , poiché in realtà non restituiscono l'oggetto stesso ma aiuta solo a tenere traccia della loro presenza in memoria .
Gli oggetti di riferimento deboli sono ideali per implementare i moduli cache. In effetti, una sorta di sfratto automatico può essere implementato consentendo al GC di ripulire le aree di memoria ogni volta che oggetti / valori non sono più raggiungibili da una forte catena di riferimenti. Un esempio è la WeakHashMap che mantiene le chiavi deboli.
Riferimento debole:
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.
Riferimento morbido:
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 rimarrà in genere per un po '.
Phantom Reference:
Un riferimento fantasma è abbastanza diverso da SoftReference o WeakReference. La sua presa sul suo oggetto è così debole che non puoi nemmeno recuperare l'oggetto - il suo metodo get () restituisce sempre null. L'unico uso per tale riferimento è tenere traccia di quando viene accodato in una ReferenceQueue, poiché a quel punto si conosce l'oggetto a cui puntava è morto.
Questo testo è stato estratto da: https://weblogs.java.net/blog/2006/05/04/understanding-weak-references
La semplice differenza tra SoftReference
e WeakReference
è fornita dallo sviluppatore Android .
La differenza tra a SoftReference
e a WeakReference
è il momento in cui viene presa la decisione di cancellare e accodare il riferimento:
A SoftReference
dovrebbe essere cancellato e accodato il più tardi possibile, cioè nel caso in cui la VM sia in pericolo di esaurire la memoria.
A WeakReference
può essere cancellato e accodato non appena si sa che ha un riferimento debole.
I tre termini che hai usato sono per lo più legati all'idoneità di Object a raccogliere Garbage.
Riferimento debole : è un riferimento non abbastanza forte da forzare l'oggetto a rimanere in memoria. Sono i capricci del raccoglitore di rifiuti a raccogliere quell'oggetto per la raccolta dei rifiuti. Non puoi forzare quel GC a non raccoglierlo .
Riferimento morbido : è più o meno lo stesso del riferimento debole. Ma puoi dire che contiene l'oggetto un po 'più fortemente del riferimento debole della garbage collection.
Se i Garbage collector raccolgono il riferimento debole nel primo ciclo di vita stesso, raccoglieranno il riferimento soft nel successivo ciclo di Garbage Collection.
Forte riferimento : è proprio l'opposto dei due precedenti tipi di riferimenti. Sono meno propensi a raccogliere i rifiuti (per lo più non vengono mai raccolti).
È possibile fare riferimento al seguente link per ulteriori informazioni:
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/Reference.html
Questo articolo può essere di grande aiuto per comprendere riferimenti forti, morbidi, deboli e fantasma.
Per darti un riepilogo,
Se hai un forte riferimento a un oggetto, l'oggetto non potrà mai essere raccolto / recuperato da GC (Garbage Collector).
Se hai solo riferimenti deboli a un oggetto (senza riferimenti forti), l'oggetto verrà recuperato da GC nel ciclo GC immediatamente successivo.
Se si hanno solo riferimenti soft a un oggetto (senza riferimenti forti), l'oggetto verrà recuperato da GC solo quando JVM esaurisce la memoria.
Creiamo riferimenti fantasma a un oggetto per tenere traccia di quando l'oggetto viene accodato nel ReferenceQueue
. Una volta che sai che puoi eseguire una finalizzazione a grana fine. (Questo ti salverebbe dalla resurrezione accidentale dell'oggetto in quanto il riferimento fantasma non ti dà il referrant). Ti consiglierei di leggere questo articolo per avere dettagli approfonditi su questo.
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
4 gradi di riferimento - Strong, Weak, Soft, Phantom
Forte: è un tipo di riferimento che rende l'oggetto referenziato non idoneo per GC. classi del costruttore. ad es. - StringBuilder
Debole: è un riferimento idoneo per GC.
Soft: è un tipo di riferimento il cui oggetto è idoneo per GC fino a quando la memoria non è disponibile. Ideale per la cache di immagini. Li terrà fino a quando la memoria non sarà disponibile.
Fantasma - è un tipo di riferimento il cui oggetto è direttamente idoneo per GC. Utilizzato solo per sapere quando un oggetto viene rimosso dalla memoria.
usi:
Consente di identificare quando un oggetto viene rimosso esattamente dalla memoria.
quando il
finalize()
metodo è sovraccarico, GC potrebbe non avvenire in modo tempestivo per gli oggetti GC ammissibili delle due classi. Quindi il riferimento fantasma li rende idonei per GC primafinalize()
, è per questo che puoi ottenere OutOfMemoryErrors anche quando la maggior parte dell'heap è spazzatura.
I riferimenti deboli sono ideali per implementare i moduli della cache.
Questi sono i tuoi normali riferimenti agli oggetti che codifichiamo quotidianamente:
Employee emp = new Employee();
La variabile "emp" contiene un forte riferimento a un oggetto Employee e gli oggetti che sono raggiungibili attraverso qualsiasi catena di riferimenti forti non sono idonei per la garbage collection. Di solito, questo è quello che vuoi ma non sempre. Ora supponiamo che stiamo recuperando un sacco di dipendenti dal database in una raccolta o in una mappa e che dobbiamo fare molti lavori su di essi regolarmente, quindi per mantenere le prestazioni li terremo nella cache.
Per quanto va bene, ma ora abbiamo bisogno di dati diversi e non abbiamo bisogno di quegli oggetti Employee e questi non sono referenziati da nessuna parte tranne la cache. Che sta causando una perdita di memoria perché questi oggetti non sono in uso ma non sono ancora idonei per la garbage collection e non possiamo rimuovere quegli oggetti dalla cache perché non abbiamo riferimenti ad essi? Quindi qui o dobbiamo svuotare manualmente l'intera cache, il che è noioso o potremmo usare altri riferimenti gentili, ad esempio riferimenti deboli.
Un riferimento debole non blocca un oggetto in memoria e verrà GCC nel ciclo GC successivo se non referenziato da altri riferimenti. Possiamo usare la classe WeakReference fornita da Java per creare sopra il tipo di cache, che non memorizzerà oggetti a cui non si fa riferimento da qualche altra parte.
WeakReference<Cache> cache = new WeakReference<Cache>(data);
Per accedere ai dati è necessario chiamare cache.get (). Questa chiamata per ottenere potrebbe restituire null se il riferimento debole è stato garbage collection: è necessario controllare il valore restituito per evitare NPE. Java fornisce raccolte che utilizzano riferimenti deboli, ad es. La classe WeakHashMap archivia le chiavi (non i valori) come riferimenti deboli. Se la chiave è GC'd, il valore verrà automaticamente rimosso anche dalla mappa.
Poiché anche i riferimenti deboli sono oggetti, abbiamo bisogno di un modo per ripulirli (non sono più utili quando l'oggetto a cui si riferivano è stato GC). Se si passa un ReferenceQueue nel costruttore per un riferimento debole, il garbage collector aggiungerà quel riferimento debole al ReferenceQueue prima che vengano finalizzati o GC. È possibile elaborare periodicamente questa coda e gestire riferimenti non funzionanti.
Un SoftReference è come un WeakReference ma è meno probabile che venga raccolto. I riferimenti software vengono cancellati a discrezione del garbage collector in risposta alla richiesta di memoria. La macchina virtuale garantisce che tutti i riferimenti software ad oggetti dolcemente raggiungibili saranno cancellati prima di lanciare un OutOfMemoryError.
I riferimenti fantasma sono i più deboli di tutti i tipi di riferimento, la chiamata get su di essi restituirà sempre null. A un oggetto viene fatto riferimento fantasma dopo che è stato finalizzato, ma prima che la sua memoria allocata sia stata recuperata, al contrario di riferimenti deboli che sono accodati prima che siano finalizzati o che i riferimenti Phantom di GC vengono usati raramente.
Quindi come sono utili? Quando costruisci un riferimento fantasma devi sempre passare un ReferenceQueue. Questo indica che puoi usare un riferimento fantasma per vedere quando il tuo oggetto è GC'd.
Ehi, quindi se i riferimenti deboli vengono accodati quando vengono considerati finalizzati ma non ancora GC, potremmo creare un nuovo riferimento forte all'oggetto nel blocco finalizzatore e impedire che l'oggetto venga GC. Sì, puoi ma probabilmente non dovresti farlo. Per verificare questo caso, il ciclo GC avverrà almeno due volte per ciascun oggetto, a meno che quell'oggetto non sia raggiungibile solo con un riferimento fantasma. Questo è il motivo per cui puoi rimanere senza heap anche quando la tua memoria contiene molta spazzatura. I riferimenti fantasma possono impedirlo.
Puoi leggere di più sul mio articolo Tipi di riferimenti in Java (Strong, Soft, Weak, Phantom) .