2013-07-25 15 views
5

İşte benim kod Çok garip, rq.remove() sonsuza engellenecektir oluyorNihai bir nesne için neden PhantomReference'ı ReferenceQueue'dan alamıyorum?

public class FinalizableObject { 

    @Override 
    protected void finalize() throws Throwable { 
     System.out.println("finalize() invoked for " + this); 
     super.finalize(); 
    } 
} 

public class Main { 
    private static void test() throws InterruptedException { 
     ReferenceQueue<FinalizableObject> rq = new ReferenceQueue<FinalizableObject>(); 
     FinalizableObject obj = new FinalizableObject(); 
     PhantomReference<FinalizableObject> pr1 = new PhantomReference<FinalizableObject>(obj, rq); 
     obj = null; 
     System.gc(); 
     Reference<? extends Object> ref = rq.remove(); 
     System.out.print("remove " + ref + " from reference queue\n"); 
    } 
    public static void main(String[] args) { 
     try { 
      test(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

olduğunu. Sonuçlandırılabilir nesnemin fantom referansı neden referans sırasına konamaz? GC toplandı mı?

cevap

1

Sorun, önemsiz olmayan finalize() yönteminizdir. Varsayılan uygulamada (Object sınıfında) bu yöntem aslında boştur. Uygulaması boş olmadığında, finalize()'u çağırdıktan sonra nesnenin hemen toplanacağı garanti edilmez.

böyle bir tarzda programı değiştirerek olacaksa:

for (int i = 0; i < 1000; i++) 
     System.gc(); 

yani tek kat daha sonra GC arayacak - (benim makinede testi) tam toplanacak rq nesneye yol açabilir. Ayrıca

, sana keşfetmeye bağlantıları takip öneririz:

  1. Java: PhantomReference, ReferenceQueue and finalize
  2. Discovering Objects with Non-trivial Finalizers
  3. The Secret Life Of The Finalizer: page 2 of 2

UPD: bir başka yolu: Eğer aklınızda tutmak zorunda önemsiz olmayan finalize() yöntemleri, aynı zamanda özel bir Finalizer-Thread tarafından çağrılır toplanacak ave. Yani, toplama tam pr için böyle şeyler yapabilirsiniz:

a) Main yöntemi içinde bayrağı oluşturun:

@Override 
protected void finalize() throws Throwable { 
    System.out.println("finalize() invoked for " + this); 
    super.finalize(); 
    Main.flag = true; 
} 

c) bayrağı denetlemek: finalize() yöntemde

public static volatile boolean flag; 

b) grubu bayrağı true ve sonra gc() numaralı telefonu yeniden arayın:

System.gc(); 
    while (!flag) Thread.sleep(10); 
    System.gc(); 
+0

Çok teşekkür ederim.
FinalizerReferenceQueue ve FinalizerDeamon'u biliyorum, GC'nin 2 katı tamamlanmış bir nesneyi tam olarak toplayabilir. Ama neden 100 kez GC'nin toplanmasını tetikleyeceğini anlayamıyorum (GC'nin 20 katı bile enseçiliği tetikleyemez).
Diğer taraftan, PhantomReference'ı WeakReference ile değiştirirsem, referansı çok hızlı bir şekilde kaldırabilir.

+0

@DevboardFan Bunun nedeni, önemsiz olmayan 'finalize()' yöntemini çağırmak için JVM'nin ayrıca toplanması ve bitirilmesi gereken özel Finalizer-Thread oluşturmasıdır. – Andremoniy

+0

Çok teşekkür ederim! –