2015-11-02 21 views

回答

6

您可以按照blog

有什麼好處是PhantomReferences?我只知道兩個嚴重的情況 他們:首先,它們允許您確定何時從內存中刪除對象 。他們實際上是確定 的唯一方法。這通常不是很有用,但在某些非常特殊的情況下可能會派上用場,比如操縱大圖像:如果您確實知道圖像應該被垃圾收集,您可以等待,直到它實際上在嘗試加載之前下一個圖像, ,因此使可怕的OutOfMemoryError不太可能。其次,PhantomReferences避免了一個基本問題,最終確定:finalize()方法可以通過創建 新的強引用來重新生成對象。那麼,你說什麼?那麼,問題是 ,重寫finalize()的對象現在必須被確定爲 至少在兩個單獨的垃圾回收循環中進行垃圾回收,以便收集到 。當第一個週期確定它是垃圾時, 有資格完成。由於在定稿過程中對象「復活」 的可能性(slim,但不幸實際),垃圾收集器必須在 對象實際被刪除之前再次運行。由於最終定稿可能不及時發生,因此在對象正在等待 定稿時可能發生任意數量的垃圾收集週期。這可能意味着在實際清理垃圾對象時出現嚴重延遲,這就是爲什麼即使大部分垃圾堆都是垃圾,您仍然可以獲取OutOfMemoryErrors。

還可以閱讀:The Mysterious Phantom Reference

考慮下面的代碼。

public class Foo { 

    private String bar; 

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

    public String foo() { 
     return bar; 
    } 
} 

因此,可以說後的對象已通過的一些 應用我想完全解除引用如何調用foo()。這裏有一些代碼,我想 預計將工作,這將與一個小竅門。

// 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需要一個Foo和ReferenceQueue的實例。由於 Foo沒有手柄,它應該立即死亡。接下來,告訴 收集虛擬機,因爲堆中沒有足夠的空間來自然觸發 集合。我要問的第一件事情是 PhantomReference是;你入隊了嗎?在這種情況下,答案 將是真實的。接下來,我要求隊列中的參考資料,但您可以參考 ,調用get()總是返回null。關於 有意義的唯一解決方案是將您想要與交互的資源或對象包含在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"); 
    } 
} 

在這種情況下,我不打算在子類來包裝美孚因爲這 似乎違反幻影的精神。相反,我要去 包裝與Foo相關的資源並與它們進行交互。現在我可以 做到這一點。

// 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(); 
}