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

今天再进一步谈一下这个几个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】:

import java.lang.ref.*;public class References { public static void main(String[] args) { Object softObj, weakObj, phantomObj; Reference ref; WeakReference weakRef; SoftReference softRef; PhantomReference phantomRef; ReferenceQueue softQueue, weakQueue, phantomQueue; softObj = new String("Soft Reference"); weakObj = new String("Weak Reference"); phantomObj = new String("Phantom Reference"); softQueue = new ReferenceQueue(); weakQueue = new ReferenceQueue(); phantomQueue = new ReferenceQueue(); softRef = new SoftReference(softObj, softQueue); weakRef = new WeakReference(weakObj, weakQueue); phantomRef = new PhantomReference(phantomObj, phantomQueue); // Print referents to prove they exist. Phantom referents // are inaccessible so we should see a null value. System.out.println("Soft Referenc: "+ softRef.get()); System.out.println("Weak Reference: " + weakRef.get()); System.out.println("Phantom Reference: " + phantomRef.get()); // Clear all strong references softObj = null; weakObj = null; phantomObj = null; // Reach object via reference System.out.println("Soft Referenc: "+ softRef.get()); System.out.println("Weak Reference: " + weakRef.get()); System.out.println("Phantom Reference: " + phantomRef.get()); // Check the queue before garbage collection System.out.println("Soft Queued: "+ softRef.isEnqueued()); System.out.println("Weak Queued: " + weakRef.isEnqueued()); System.out.println("Phantom Queued: " + phantomRef.isEnqueued()); // Invoke garbage collector in hopes that references will be queued System.gc(); // Try to finalize the phantom references if not already if (!phantomRef.isEnqueued()) { System.out.println("Requestion finalization."); System.runFinalization(); } // See if the garbage collector has queued the references System.out.println("Soft Queued: "+ softRef.isEnqueued()); System.out.println("Weak Queued: " + weakRef.isEnqueued()); System.out.println("Phantom Queued: " + phantomRef.isEnqueued()); try { // Test soft reference if(softRef.isEnqueued()){ System.out.println("Soft Referenc in the Queue"); ref = softQueue.remove(); System.out.println("Soft Queued: "+ ref.get()); } else{ System.out.println("Soft Referenc not in the Queue"); } // Test weak reference if(weakRef.isEnqueued()){ System.out.println("Weak Referenc in the Queue"); ref = weakQueue.remove(); System.out.println("Weak Reference: " + ref.get()); } else{ System.out.println("Weak Referenc not in the Queue"); } // Test Phantom reference if(phantomRef.isEnqueued()){ System.out.println("Phantom Referenc in the Queue"); ref = phantomQueue.remove(); System.out.println("Phantom Reference: " + ref.get()); // We have to clear the phantom referent even though // get() returns null ref.clear(); } else{ System.out.println("Phantom Referenc not in the Queue"); } } catch (InterruptedException e) { e.printStackTrace(); return; } } } 

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

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

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

//: containers/References.java//Demonstrates Reference objects from <Thinking in Java> 4th edition section "Holding references" import java.lang.ref.*; import java.util.*; class VeryBig { private static final int SIZE = 10000; private long[] la = new long[SIZE]; private String ident; public VeryBig(String id) { ident = id; } public String toString() { return ident; } public String getID() { return ident; } protected void finalize() { System.out.println("Finalizing " + ident); } } public class ReferencesTIJ { private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<VeryBig>(); public static void checkQueue() { Reference<? extends VeryBig> inq = rq.poll(); referenceType(inq); } private static void referenceType(Reference<? extends VeryBig> inq) { if (inq != null) { if (inq instanceof PhantomReference) System.out.println("PhantomReference In queue: " + inq.get()); if (inq instanceof WeakReference) System.out.println("WeakReference In queue: " + inq.get()); if (inq instanceof SoftReference) System.out.println("SoftReference In queue: " + inq.get()); } } public static void main(String[] args) { int size = 10; // Or, choose size via the command line: if (args.length > 0) size = new Integer(args[0]); LinkedList<SoftReference<VeryBig>> sa = new LinkedList<SoftReference<VeryBig>>(); for (int i = 0; i < size; i++) { sa.add(new SoftReference<VeryBig>(new VeryBig("Soft " + i), rq)); System.out.println("Just created <" + i + "> : " + sa.getLast().toString()); checkQueue(); } LinkedList<WeakReference<VeryBig>> wa = new LinkedList<WeakReference<VeryBig>>(); for (int i = 0; i < size; i++) { wa.add(new WeakReference<VeryBig>(new VeryBig("Weak " + i), rq)); System.out.println("Just created <" + i + "> : " + wa.getLast().toString()); checkQueue(); } SoftReference<VeryBig> s = new SoftReference<VeryBig>(new VeryBig( "Soft Last")); WeakReference<VeryBig> w = new WeakReference<VeryBig>(new VeryBig( "Weak Last")); System.gc(); LinkedList<PhantomReference<VeryBig>> pa = new LinkedList<PhantomReference<VeryBig>>(); for (int i = 0; i < size; i++) { pa.add(new PhantomReference<VeryBig>(new VeryBig("Phantom " + i), rq)); System.out.println("Just created <" + i + "> : " + pa.getLast()); } //System.runFinalization(); Reference<? extends VeryBig> ref; while ((ref = rq.poll()) != null) { if (ref != null) { referenceType(ref); } } } }  

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