WeakReference,SoftReference 和 PhatomReference 浅析

本文深入探讨Java中的SoftReference、WeakReference及PhantomReference,通过示例代码展示不同引用类型的生命周期和垃圾回收机制。

转自: http://blog.csdn.net/autofei/article/details/6358863

 

前几天发了一篇关于垃圾收集的帖子,自己也不是这方面的专家,所以肯定有很多问题和错误,也请大家多多包涵和指教。

今天再进一步谈一下这个几个Reference吧。老实说,这几个名词我也是最近才听说,平时也没有实际使用过,但是确实在java 1.2就存在的,看来真的是学无止境啊。

 

  • softly reachable:The object is the referent of a SoftReference. The garbage collector will attempt to preserve the object as long as possible, but will collect it before throwing an OutOfMemoryError.
  • weakly reachable:The object is the referent of a WeakReference, and there are no strong or soft references to it. The garbage collector is free to collect the object at any time, with no attempt to preserve it.
  • phantom reachable:The object is the referent of a PhantomReference, and there are no strong, soft, or weak references to it. This reference type differs from the other two in that it isn't meant to be used to access the object, but as a signal that the object has already been finalized, and the garbage collector is ready to reclaim its memory.

 

在《Thinking in Java》第四版是如此描述:In the order of SoftReference, WeakReference, and PhantomReference, each one is "weaker" than the last and corresponds to a different level of reachability. Soft references are for implementing memory-sensitive caches. Weak references are for implementing "canonicalizing mappings"—where instances of objects can be simultaneously used in multiple places in a program, to save storage—that do not prevent their keys (or values) from being reclaimed. Phantom references are for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism.

 

在引入了这几个引用之后,对象的生命周期【1】:

  1. import java.lang.ref.*;  
  2. public class References {  
  3.     public static void main(String[] args) {  
  4.         Object softObj, weakObj, phantomObj;  
  5.         Reference ref;  
  6.         WeakReference weakRef;  
  7.         SoftReference softRef;  
  8.         PhantomReference phantomRef;  
  9.         ReferenceQueue softQueue, weakQueue, phantomQueue;  
  10.         softObj = new String("Soft Reference");  
  11.         weakObj = new String("Weak Reference");  
  12.         phantomObj = new String("Phantom Reference");  
  13.         softQueue = new ReferenceQueue();  
  14.         weakQueue = new ReferenceQueue();  
  15.         phantomQueue = new ReferenceQueue();  
  16.         softRef = new SoftReference(softObj, softQueue);  
  17.         weakRef = new WeakReference(weakObj, weakQueue);  
  18.         phantomRef = new PhantomReference(phantomObj, phantomQueue);  
  19.         // Print referents to prove they exist. Phantom referents   
  20.         // are inaccessible so we should see a null value.   
  21.         System.out.println("Soft Referenc: "+ softRef.get());  
  22.         System.out.println("Weak Reference: " + weakRef.get());  
  23.         System.out.println("Phantom Reference: " + phantomRef.get());  
  24.         // Clear all strong references   
  25.         softObj = null;  
  26.         weakObj = null;  
  27.         phantomObj = null;  
  28.           
  29.         // Reach object via reference   
  30.         System.out.println("Soft Referenc: "+ softRef.get());  
  31.         System.out.println("Weak Reference: " + weakRef.get());  
  32.         System.out.println("Phantom Reference: " + phantomRef.get());         
  33.         // Check the queue before garbage collection   
  34.         System.out.println("Soft Queued: "+ softRef.isEnqueued());  
  35.         System.out.println("Weak Queued: " + weakRef.isEnqueued());  
  36.         System.out.println("Phantom Queued: " + phantomRef.isEnqueued());     
  37.           
  38.         // Invoke garbage collector in hopes that references will be queued   
  39.         System.gc();  
  40.           
  41.         // Try to finalize the phantom references if not already   
  42.         if (!phantomRef.isEnqueued()) {  
  43.             System.out.println("Requestion finalization.");  
  44.             System.runFinalization();  
  45.         }  
  46.           
  47.         // See if the garbage collector has queued the references   
  48.         System.out.println("Soft Queued: "+ softRef.isEnqueued());  
  49.         System.out.println("Weak Queued: " + weakRef.isEnqueued());  
  50.         System.out.println("Phantom Queued: " + phantomRef.isEnqueued());  
  51.         try {  
  52.             // Test soft reference   
  53.             if(softRef.isEnqueued()){  
  54.                 System.out.println("Soft Referenc in the Queue");  
  55.                 ref = softQueue.remove();  
  56.                 System.out.println("Soft Queued: "+ ref.get());               
  57.             }  
  58.             else{  
  59.                 System.out.println("Soft Referenc not in the Queue");  
  60.             }  
  61.             // Test weak reference   
  62.             if(weakRef.isEnqueued()){  
  63.                 System.out.println("Weak Referenc in the Queue");  
  64.                 ref = weakQueue.remove();  
  65.                 System.out.println("Weak Reference: " + ref.get());  
  66.             }  
  67.             else{  
  68.                 System.out.println("Weak Referenc not in the Queue");  
  69.             }  
  70.               
  71.             // Test Phantom reference    
  72.             if(phantomRef.isEnqueued()){  
  73.                 System.out.println("Phantom Referenc in the Queue");  
  74.                 ref = phantomQueue.remove();  
  75.                 System.out.println("Phantom Reference: " + ref.get());  
  76.                 // We have to clear the phantom referent even though   
  77.                 // get() returns null   
  78.                 ref.clear();              
  79.             }  
  80.             else{  
  81.                 System.out.println("Phantom Referenc not in the Queue");  
  82.             }  
  83.         } catch (InterruptedException e) {  
  84.             e.printStackTrace();  
  85.             return;  
  86.         }  
  87.     }  
  88. }  
 

上面这段代码演示了几种引用的特性:

  • PhantomReference总是返回null
  • 垃圾收集之后PhantomReferenceWeakReference都进去了queue,而SoftReference没有。证明SoftReference生命周期更长。

下面这个例子来自《Thinking in Java》第四版,稍作修改:

  1. //: containers/References.java   
  2. //Demonstrates Reference objects from <Thinking in Java> 4th edition section "Holding references"   
  3. import java.lang.ref.*;  
  4. import java.util.*;  
  5. class VeryBig {  
  6.     private static final int SIZE = 10000;  
  7.     private long[] la = new long[SIZE];  
  8.     private String ident;  
  9.     public VeryBig(String id) {  
  10.         ident = id;  
  11.     }  
  12.     public String toString() {  
  13.         return ident;  
  14.     }  
  15.     public String getID() {  
  16.         return ident;  
  17.     }  
  18.     protected void finalize() {  
  19.         System.out.println("Finalizing " + ident);  
  20.     }  
  21. }  
  22. public class ReferencesTIJ {  
  23.     private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<VeryBig>();  
  24.     public static void checkQueue() {  
  25.         Reference<? extends VeryBig> inq = rq.poll();  
  26.         referenceType(inq);  
  27.     }  
  28.     private static void referenceType(Reference<? extends VeryBig> inq) {  
  29.         if (inq != null) {  
  30.             if (inq instanceof PhantomReference)  
  31.                 System.out.println("PhantomReference In queue: " + inq.get());  
  32.             if (inq instanceof WeakReference)  
  33.                 System.out.println("WeakReference In queue: " + inq.get());  
  34.             if (inq instanceof SoftReference)  
  35.                 System.out.println("SoftReference In queue: " + inq.get());  
  36.         }  
  37.     }  
  38.     public static void main(String[] args) {  
  39.         int size = 10;  
  40.         // Or, choose size via the command line:   
  41.         if (args.length > 0)  
  42.             size = new Integer(args[0]);  
  43.         LinkedList<SoftReference<VeryBig>> sa = new LinkedList<SoftReference<VeryBig>>();  
  44.         for (int i = 0; i < size; i++) {  
  45.             sa.add(new SoftReference<VeryBig>(new VeryBig("Soft " + i), rq));  
  46.             System.out.println("Just created <" + i + "> : "  
  47.                     + sa.getLast().toString());  
  48.             checkQueue();  
  49.         }  
  50.         LinkedList<WeakReference<VeryBig>> wa = new LinkedList<WeakReference<VeryBig>>();  
  51.         for (int i = 0; i < size; i++) {  
  52.             wa.add(new WeakReference<VeryBig>(new VeryBig("Weak " + i), rq));  
  53.             System.out.println("Just created <" + i + "> : "  
  54.                     + wa.getLast().toString());  
  55.             checkQueue();  
  56.         }  
  57.         SoftReference<VeryBig> s = new SoftReference<VeryBig>(new VeryBig(  
  58.                 "Soft Last"));  
  59.         WeakReference<VeryBig> w = new WeakReference<VeryBig>(new VeryBig(  
  60.                 "Weak Last"));  
  61.           
  62.         System.gc();  
  63.           
  64.         LinkedList<PhantomReference<VeryBig>> pa = new LinkedList<PhantomReference<VeryBig>>();  
  65.         for (int i = 0; i < size; i++) {  
  66.             pa.add(new PhantomReference<VeryBig>(new VeryBig("Phantom " + i),  
  67.                     rq));  
  68.             System.out.println("Just created <" + i + "> : " + pa.getLast());  
  69.         }  
  70.           
  71.         //System.runFinalization();   
  72.         Reference<? extends VeryBig> ref;  
  73.         while ((ref = rq.poll()) != null) {  
  74.             if (ref != null) {  
  75.                 referenceType(ref);  
  76.             }  
  77.         }  
  78.     }  
  79. }  
 

这个例子比较有意思,每次执行,结果都会有一些差异。至于为什么,我也在研究之中,欢迎大家指教!

 

参考:

【1】http://www.kdgregory.com/index.php?page=java.refobj

【2】http://improving.iteye.com/blog/436311

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值