Java: differenza tra riferimento forte / morbido / debole / fantasma


179

Ho letto questo articolo sull'argomento, ma non lo capisco davvero. Per favore, dammi qualche consiglio insieme ad esempi quando descrivo i concetti.



4
Ho letto quel documento, non mi aiuta a immaginare quale differenza. (forse perché è un documento di difficile lettura)

14
Se leggi quell'articolo e ancora non capisci, hai domande specifiche a riguardo? È difficile rispondere a "spiegami Foo", "ecco cosa significa", "non capisco" senza dettagli su quali parti non ottieni.
yshavit,


@LouisWasserman Il collegamento superiore non è più valido.
Mehraj Malik,

Risposte:


142

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 .

  • Forte
  • Debole
    • morbido
    • 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' StringBuilderoggetto in memoria sia, in realtà, il riferimento debole, quindi al GC è consentito eseguire il garbage collection StringBuilderdell'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.


76

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


1
Mentre tutto in questa risposta sembra corretto, mi sembra anche che ci possa essere un errore sulla pagina web collegata. Il Javadoc per il pacchetto java.lang.ref e quello per PhantomReference suggeriscono che un oggetto non è spazzatura raccolto fino a quando non è più "raggiungibile da un fantasma", il che implica che (a differenza di SoftReference) un PhantomReference deve essere rimescolato prima che l'oggetto a cui si riferisce possa essere spazzatura raccolta ... e il fatto che sia accodato non indica che la memoria associata è stata liberata.
Theodore Murdock,

2
Per la cronaca, preferirei di gran lunga vivere in un mondo in cui quel post sul blog è corretto.
Theodore Murdock,

1
@TheodoreMurdock Il javadoc è corretto. Un riferimento fantasma non impedisce affatto la garbage collection. Una volta accodato, un oggetto non può essere salvato nemmeno da un finalizzatore, poiché i finalizzatori sono già in esecuzione. È morto, ma non ancora andato.
Leliel

@Leliel In realtà, un riferimento fantasma fa , infatti, la raccolta dei rifiuti impediscono dopo che è stato inserito nella coda ... ho capito questo recente, quando un bug ha causato un thread di pulitura di uscita anticipata. L'esistenza di riferimenti fantasma era sufficiente per garantire che ogni oggetto fantasma referenziato fosse conservato nel mio dump dell'heap, non disponibile per la raccolta ... se non si riesce a elaborare la coda o non si rende idoneo il riferimento fantasma per gc durante l'elaborazione della coda ( e non cancellare () il riferimento fantasma), quindi la perdita di memoria includerà sia il riferimento fantasma che l'oggetto di riferimento.
Theodore Murdock,

25

La semplice differenza tra SoftReferencee WeakReferenceè fornita dallo sviluppatore Android .

La differenza tra a SoftReferencee a WeakReferenceè il momento in cui viene presa la decisione di cancellare e accodare il riferimento:

  • A SoftReferencedovrebbe essere cancellato e accodato il più tardi possibile, cioè nel caso in cui la VM sia in pericolo di esaurire la memoria.

  • A WeakReferencepuò essere cancellato e accodato non appena si sa che ha un riferimento debole.


16

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


3
Penso che sia sbagliato - "Se i Garbage collector raccolgono il riferimento debole nel primo ciclo di vita stesso, raccoglieranno il riferimento morbido nel prossimo ciclo di Garbage collection". Non è necessariamente così, come puoi essere così sicuro che si verifichino in serie consecutive di GC? GC può consentire agli oggetti con riferimento morbido di vivere anche nella 2a e 3a corsa. Non c'è documentazione per esso, se c'è allora si prega di menzionare il link che specifica.
Saurabh Patil,

2
Inoltre, la tua risposta è un po 'vaga, guarda questa frase "È più o meno uguale al riferimento debole. Ma puoi dire che contiene l'oggetto un po 'più fortemente del riferimento debole della garbage collection.' - sta chiaramente chiedendo della differenza e non delle somiglianze, tutte queste parole aggiungono più confusione che chiarezza all'argomento.
Saurabh Patil,

@SaurabhPatil - Ha perso il tuo commento. Ecco le risposte. 1. "sta chiaramente chiedendo la differenza e non le somiglianze" - Fai riferimento alla descrizione della domanda (non "solo" il titolo) "Per favore, dammi qualche consiglio, e per favore, dammi qualche esempio per descriverlo". 2. "Ma puoi dire che contiene l'oggetto un po 'di più ...." Penso che SOF offra un'opzione per votare in negativo e dare anche nuove risposte.
Sabya,

14

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

  • Cameriere - GC
  • Tu - Oggetto nell'heap
  • Area ristorante / spazio - Heap space
  • Nuovo cliente: nuovo oggetto che desidera un tavolo nel 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


10

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:

  1. Consente di identificare quando un oggetto viene rimosso esattamente dalla memoria.

  2. 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 prima finalize(), è 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.


10

Riferimenti forti

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.

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.

Riferimenti morbidi

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.

Riferimenti fantasma

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) .


hai scritto che i riferimenti deboli verranno GC nel ciclo successivo se non si rifrangono da altri riferimenti ... ma non dovrebbe accadere la stessa cosa per migliorare i riferimenti? se non si accede in alcun modo alla rifrazione dello stron, allora viene cancellato ... allora, allora dov'è di nuovo la differenza ...? #confused
filemonczyk il

1
Se un oggetto viene referenziato diciamo s1 (strong) e s2 (strong), l'oggetto non sarà idoneo per la garbage collection fino a quando sia s1 che s2 saranno sottoposti a dereferenziazione, ma se l'oggetto viene referenziato da s1 (debole) e s2 ( strong), quindi l'oggetto sarà idoneo per la garbage collection nel successivo ciclo GC quando viene deferenziato solo da s2, poiché s1 è un riferimento debole e se l'oggetto non ha altri riferimenti tranne quello debole, è idoneo per GC
Naresh Joshi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.