2015-11-02 13 views

risposta

6

Puoi seguire questa blog:

cosa servono PhantomReferences? Sono a conoscenza solo di due casi gravi per loro: in primo luogo, consentono di determinare esattamente quando un oggetto è stato rimosso dalla memoria. Sono infatti l'unico modo per determinare quello . Questo non è generalmente utile, ma potrebbe essere utile in alcune circostanze molto specifiche come la manipolazione di immagini di grandi dimensioni: se si sa per certo che un'immagine deve essere raccolta dei dati inutili, è possibile attendere fino a quando non è effettivamente prima di tentare di caricare l'immagine successiva, e quindi rende meno probabile il temuto OutOfMemoryError.

In secondo luogo, PhantomReferences evitare un problema fondamentale con finalizzazione: finalizzare() metodi possono "resuscitare" gli oggetti con la creazione di nuovi forti riferimenti ad essi. Quindi cosa dici? Bene, il problema è che un oggetto che sovrascrive finalize() deve ora essere determinato per essere immondizia in almeno due cicli di garbage collection separati al fine di raccogliere . Quando il primo ciclo determina che è spazzatura, diventa disponibile per la finalizzazione . A causa della (sottile, ma purtroppo reale) possibilità che l'oggetto fosse "resuscitato" durante la finalizzazione, il garbage collector deve essere eseguito nuovamente prima che l'oggetto possa essere effettivamente rimosso. E poiché la finalizzazione potrebbe non essere stata eseguita in modo tempestivo, , un numero arbitrario di cicli di raccolta di immondizia potrebbe essersi verificato mentre l'oggetto era in attesa della finalizzazione . Questo può significare seri ritardi nella pulizia degli oggetti inutili di ed è il motivo per cui è possibile ottenere OutOfMemoryErrors anche quando la maggior parte dell'heap è spazzatura.

Leggi anche: The Mysterious Phantom Reference

Si consideri il seguente codice.

public class Foo { 

    private String bar; 

    public Foo(String bar) { 
     this.bar = bar; 
    } 

    public String foo() { 
     return bar; 
    } 
} 

Allora supponiamo dopo che l'oggetto è stato completamente dereferenziati dal applicazione che voglio in qualche modo chiamare foo(). Ecco un codice che I si aspettava che funzionasse con una sola pecca.

// initialize 
ReferenceQueue<Foo> queue = new ReferenceQueue<Foo>(); 
ArrayList< PhantomReference<Foo>> list=new ArrayList<PhantomReference<Foo>>(); 

for (int i = 0; i < 10; i++) { 
    Foo o = new Foo(Integer.toOctalString(i)); 
    list.add(new PhantomReference<Foo>(o, queue)); 
} 

// make sure the garbage collector does it’s magic 
System.gc(); 

// lets see what we’ve got 
Reference<? extends Foo> referenceFromQueue; 
for (PhantomReference<Foo> reference : list) 
    System.out.println(reference.isEnqueued()); 

while ((referenceFromQueue = queue.poll()) != null) { 
    System.out.println(referenceFromQueue.get()); 
    referenceFromQueue.clear(); 
} 

PhantomReference prende un'istanza di Foo e un ReferenceQueue. Dal nessuna maniglia viene mantenuta su Foo, dovrebbe essere immediatamente morta. Quindi, dire alla la VM da raccogliere perché non c'è abbastanza heap per attivare una collezione in modo naturale. La prima cosa che chiederò al PhantomReference è; sei stato agganciato? In questo caso la risposta sarà vera. Successivamente chiedo la coda per il riferimento ma, come potete vedere, la chiamata get() restituisce sempre null. Informazioni sull'unica soluzione che aveva il valore era racchiudere le risorse o gli oggetti che si desideravano interagire con in una sottoclasse di PhantomReference.

public class FinalizeStuff<Foo> extends PhantomReference<Foo> { 

    public FinalizeStuff(Foo foo, ReferenceQueue<? super Foo> queue) { 
     super(foo, queue); 
    } 

    public void bar() { 
     System.out.println("foobar is finalizing resources"); 
    } 
} 

In questo caso non ho intenzione di avvolgere Foo nella sottoclasse come che sembrano violare lo spirito di PhantomReference. Invece vado a avvolgere le risorse associate a Foo e interagire con loro. Ora posso fare questo.

// initialize 
ReferenceQueue<Foo> queue = new ReferenceQueue<Foo>(); 
ArrayList< FinalizeStuff<Foo>> list = new ArrayList<FinalizeStuff<Foo>>(); 
ArrayList<Foo> foobar = new ArrayList<Foo>(); 

for (int i = 0; i < 10; i++) { 
    Foo o = new Foo(Integer.toOctalString(i)); 
    foobar.add(o); 
    list.add(new FinalizeStuff<Foo>(o, queue)); 
} 

// release all references to Foo and make sure the garbage collector does it’s magic 
foobar = null; 
System.gc(); 

// should be enqueued 
Reference<? extends Foo> referenceFromQueue; 
for (PhantomReference<Foo> reference : list) { 
    System.out.println(reference.isEnqueued()); 
} 

// now we can call bar to do what ever it is we need done 
while ((referenceFromQueue = queue.poll()) != null) { 
    ((FinalizeStuff)referenceFromQueue).bar(); 
    referenceFromQueue.clear(); 
} 
Problemi correlati