Strong / Soft / Weak / Phantom Reference

  java.lang.ref库中的SoftReferenceWeakReferencePhantomReference提供了更灵活的垃圾回收方式,他们继承自抽象类Reference,按照引用的强度依次递减。

1. Strong Reference

  平时使用最多的就是强引用(Strong Reference),如:

Random rand = new Random(47);

  当对象可以通过强引用可及时,该对象就不会被垃圾回收。有时候强引用会显得“过强”,比如实现一个图像缓存,缓存中保存了对图像的引用,当图像不再使用时,如果缓存中还保存了对该图像的强引用,图像就不会被垃圾回收,需要手动断开缓存中的引用。

2. WeakReference

  弱引用(WeakReference)不会强制对象留存在内存中,当对象只能通过弱引用可及时,对象就可以被垃圾回收。可以通过下面的方式建立弱引用:

WeakReference<VeryBig> w = new WeakReference<VeryBig>(new VeryBig("Weak"));

然后就可以通过w.get()获取引用。如果w.get()返回了null,就说明对象被垃圾回收了。

  Weak Reference常用于实现规范映射(Canonicalized Mapping),每一个值只有一个实例,当程序需要某个值时,就会查询并返回该值得实例,不会创建新的实例,从而节省了存储空间。Java内置了WeakHashMap,其中的键使用了弱引用,当键成为垃圾时,整个条目就会被删除。

3. SoftReference

  软引用(SoftReference)和弱引用类似,但更倾向于保留对象。只能被弱引用可及的对象会在下一次垃圾回收中被丢弃;只能被软引用可及的对象一般会多保留一段时间,通常是在急需内存时才被回收。软引用适合用于缓存,由垃圾回收机制决定对象是否可及,以及在何时被回收。

4. PhantomReference

  虚引用(PhantomReference)对对象的引用更加弱,PhantomReferenceget()始终返回null,无法通过虚引用来获取对象。虚引用只能和ReferenceQueue一起使用。

5. ReferenceQueue

  垃圾回收器可以在对象的可及性发生特定的改变时,把对象的引用加入到ReferenceQueue。ReferenceQueue可以记录被回收对象的引用。

  如果在WeakReference的构造器中指定一个ReferenceQueue,那么当该WeakReference指向的对象变为垃圾时,该对象就会被自动加入到所指定的ReferenceQueue中,之后就可以通过这个ReferenceQueue来为死引用(Dead Reference)进行清理工作。

  也可以为PhantomReference的构造器中指定一个ReferenceQueue,这里与上面使用WeakReference的区别在于入队的时机。WeakReference会在对象只能被弱引用可及时立即入队,这发生在finalize()和垃圾回收之前,这时如果再为对象建立一个强引用,就可以防止对象被回收(这是很不规范的做法)。而PhantomReference只会在对象被从内存上移除后入队,PhantomReferenceget()始终返回null,也就防止了把对象从垃圾回收中“挽救”回来的行为。

  PhantomReference可以用于判断对象被从内存上移除的时刻,如在操作体积巨大的类的时候,可以在一个类被实际从内存上移除后,再加载新的类,避免内存不足的情况。PhantomReference还阻止了在finalize()为即将被回收的对象建立强引用、从而妨碍对象被回收的行为。

6. 用例

  下面是一个来自Thinking in Java中Containers in Depth一章的例子。

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; }
    protected void finalize() {
        System.out.println("Finalizing " + ident);
    }
}

public class References {
    private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<VeryBig>();

    public static void checkQueue() {
        Reference<? extends VeryBig> inq = rq.poll();
        if(inq != null)
            System.out.println("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: " + sa.getLast());
            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: " + wa.getLast());
            checkQueue();
        }

        SoftReference<VeryBig> s = new SoftReference<VeryBig>(new VeryBig("Soft"));
        WeakReference<VeryBig> w = new WeakReference<VeryBig>(new VeryBig("Weak"));

        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: " + pa.getLast());
            checkQueue();
        }
    }
}
/* Output from OS X 10.11 + JDK 8
Just created: java.lang.ref.SoftReference@60e53b93
Just created: java.lang.ref.SoftReference@5e2de80c
Just created: java.lang.ref.SoftReference@1d44bcfa
Just created: java.lang.ref.SoftReference@266474c2
Just created: java.lang.ref.SoftReference@6f94fa3e
Just created: java.lang.ref.SoftReference@5e481248
Just created: java.lang.ref.SoftReference@66d3c617
Just created: java.lang.ref.SoftReference@63947c6b
Just created: java.lang.ref.SoftReference@2b193f2d
Just created: java.lang.ref.SoftReference@355da254
Just created: java.lang.ref.WeakReference@4dc63996
Just created: java.lang.ref.WeakReference@d716361
Just created: java.lang.ref.WeakReference@6ff3c5b5
Just created: java.lang.ref.WeakReference@3764951d
Just created: java.lang.ref.WeakReference@4b1210ee
Just created: java.lang.ref.WeakReference@4d7e1886
Just created: java.lang.ref.WeakReference@3cd1a2f1
Just created: java.lang.ref.WeakReference@2f0e140b
Just created: java.lang.ref.WeakReference@7440e464
Just created: java.lang.ref.WeakReference@49476842
Just created: java.lang.ref.PhantomReference@78308db1
Finalizing Weak
Finalizing Weak 9
Finalizing Weak 8
Finalizing Weak 7
Finalizing Weak 6
Finalizing Weak 5
Finalizing Weak 4
Finalizing Weak 3
Finalizing Weak 2
Finalizing Weak 1
Finalizing Weak 0
In queue: null
Just created: java.lang.ref.PhantomReference@27c170f0
In queue: null
Just created: java.lang.ref.PhantomReference@5451c3a8
In queue: null
Just created: java.lang.ref.PhantomReference@2626b418
In queue: null
Just created: java.lang.ref.PhantomReference@5a07e868
In queue: null
Just created: java.lang.ref.PhantomReference@76ed5528
In queue: null
Just created: java.lang.ref.PhantomReference@2c7b84de
In queue: null
Just created: java.lang.ref.PhantomReference@3fee733d
In queue: null
Just created: java.lang.ref.PhantomReference@5acf9800
In queue: null
Just created: java.lang.ref.PhantomReference@4617c264
In queue: null
*/

1 Comment

  1. QQ651018067

    博客不错,嘎嘎!

Comments are closed.