Java中三个引用类SoftReference 、 WeakReference 和 PhantomReference的区别

本文将谈一下对 SoftReference( 软引用 ) WeakReference( 弱引用 ) PhantomRefrence( 虚引用 ) 的理解 , 这三个类是对 heap java 对象的应用 通过这个三个类可以和 gc 做简单的交互。

强引用:
除了上面提到的三个引用之外 , 还有一个引用 , 也就是最长用到的那就是强引用 . 例如:
Java 代码  
1.Object o=new Object();   
2.Object o1=o;   
 
上面代码中第一句是在 heap 堆中创建新的 Object 对象通过 o 引用这个对象 第二句是通过 o 建立 o1 new Object() 这个 heap 堆中的对象的引用 这两个引用都是强引用 . 只要存在对 heap 中对象的引用 gc 就不会收集该对象 . 如果通过如下代码:
Java 代码  
1.o=null;   
2.o1=null;   
 
如果显式地设置 o o1 null 或超出范围 gc 认为该对象不存在引用 ,这时 就可以收集它了。可以收集并不等于就一会被收集 什么时候收集这要取决于 gc 的算法 这要就带来很多不确定性。例如你就想指定一个对象,希望下次 gc 运行时把它收集了,那就没办法了,有了其他的三种引用就可以做到了。其他三种引用在不妨碍 gc 收集的情况下 可以做简单的交互
heap 中对象有强可及对象、软可及对象、弱可及对象、虚可及对象和不可到达对象。应用的强弱顺序是 强、软、弱、和虚 。对于对象是属于哪种可及的对象,由他的最强的引用决定。如
Java 代码  
1.String abc=new String("abc");  //1   
2.SoftReference abcSoftRef=new SoftReference(abc);  //2   
3.WeakReference abcWeakRef = new WeakReference(abc); //3   
4.abc=null; //4   
5.abcSoftRef.clear();//5 
 
上面的代码中:
      第一行在 heap 对中创建内容为 “abc” 的对象,并建立 abc 到该对象的强引用 , 该对象是强可及的。
      第二行和第三行分别建立对 heap 中对象的软引用和弱引用 此时 heap 中的对象仍是强可及的
      第四行之后 heap 中对象不再是强可及的,变成软可及的。同样第五行执行之后变成弱可及的。
SoftReference ( 软引用 )
软引用是主要用于内存敏感的高速缓存 jvm 报告内存不足之前会清除所有的软引用 这样以来 gc 就有可能收集软可及的对象 可能解决内存吃紧问题 避免内存溢出 什么时候会被收集取决于 gc 的算法和 gc 运行时可用内存的大小 gc 决定要收集软引用是执行以下过程 , 以上面的 abcSoftRef 为例

    1   首先将 abcSoftRef referent 设置为 null 不再引用 heap 中的 new String("abc") 对象
    2   heap 中的 new String("abc") 对象设置为可结束的 (finalizable)
    3   heap 中的 new String("abc") 对象的 finalize() 方法被运行而且该对象占用的内存被释放,   abcSoftRef 被添加到它的 ReferenceQueue

    : ReferenceQueue 软引用和弱引用可以有可无 但是虚引用必须有 ,参 见:
Java 代码  
Reference(T paramT, ReferenceQueueparamReferenceQueue)   
 
  Soft Reference   指到的对象,即使没有任何   Direct Reference ,也不会被清除。一直要到   JVM   内存不足且 没有   Direct Reference   时才会清除, SoftReference   是用来设计   object-cache   之用的。如此一来 SoftReference   不但可以把对象   cache   起来,也不会造成内存不足的错误   OutOfMemoryError )。我觉得 Soft Reference   也适合拿来实作   pooling   的技巧。
     A obj = new A();
SoftRefenrence sr = new SoftReference(obj);
 
      引用
    if(sr!=null){
        obj = sr.get();
    }else{
        obj = new A();
        sr = new SoftReference(obj);
    }
 
弱引用
gc 碰到弱可及对象 并释放 abcWeakRef 的引用 收集该对象。但是 gc 可能需要对此运用才能找到该弱可及对象 通过如下代码可以了明了的看出它的作用
Java 代码  
1.String abc=new String("abc");   
2.WeakReference abcWeakRef = new WeakReference(abc);   
3.abc=null;   
4.System.out.println("before gc: "+abcWeakRef.get());   
5.System.gc();   
6.System.out.println("after gc: "+abcWeakRef.get());   
 
运行结果 :   
before gc: abc   
after gc: null   
gc 收集弱可及对象的执行过程和软可及一样 只是 gc 不会根据内存情况来决定是不是收集该对象
如果你希望能随 取得某 象的信息,但又不想影响此 象的垃圾收集,那 应该   Weak   Reference   住此 象,而不是用一般的   reference
A obj = new A();
 
    WeakReference wr = new WeakReference(obj);
 
    obj = null;
 
    // 等待一段 时间, obj 对象就会被垃圾回收
   ...
 
   if (wr.get()==null) {
   System.out.println("obj   经被清除了   ");
   } else {
   System.out.println("obj   尚未被清除,其信息是   "+obj.toString());
   }
   ...
}
在此例中,透过   get()   可以取得此   Reference   的所指到的对象,如果返回值为   null   的话,代表此对象已经被清除。
这类的技巧,在设计   Optimizer     Debugger   这类的程序时常会用到,因为这类程序需要取得某对象的信息,但是不可以   影响此对象的垃圾收集。
 
 PhantomRefrence( 虚引用 )
   虚顾名思义就是没有的意思 建立虚引用之后通过 get 方法返回结果始终为 null, 通过源代码你会发现 , 虚引用通向会把引用的对象写进 referent, 只是 get 方法返回结果为 null. 先看一下和 gc 交互的过程在说一下他的作用 .

  1   不把 referent 设置为 null,   直接把 heap 中的 new String("abc") 对象设置为可结束的 (finalizable).

  2   与软引用和弱引用不同 ,   先把 PhantomRefrence 对象添加到它的 ReferenceQueue . 然后在释放虚可及的对象 .

    你会发现在收集 heap 中的 new String("abc") 对象之前 , 你就可以做一些其他的事情 . 通过以下代码可以了解他的作用 .
Java 代码  
1.import java.lang.ref.PhantomReference;   
2.import java.lang.ref.Reference;   
3.import java.lang.ref.ReferenceQueue;   
4.import java.lang.reflect.Field;   
5.   
6.public class Test {   
7.    public static boolean isRun = true;   
8.   
9.    public static void main(String[] args) throws Exception {   
10.        String abc = new String("abc");   
11.        System.out.println(abc.getClass() + "@" + abc.hashCode());   
12.        final ReferenceQueue referenceQueue = new ReferenceQueue();   
13.        new Thread() {   
14.            public void run() {   
15.                while (isRun) {   
16.                    Object o = referenceQueue.poll();   
17.                    if (o != null) {   
18.                        try {   
19.                            Field rereferent = Reference.class   
20.                                    .getDeclaredField("referent");   
21.                            rereferent.setAccessible(true);   
22.                            Object result = rereferent.get(o);   
23.                            System.out.println("gc will collect:"   
24.                                    + result.getClass() + "@"   
25.                                    + result.hashCode());   
26.                        } catch (Exception e) {   
27.   
28.                            e.printStackTrace();   
29.                        }   
30.                    }   
31.                }   
32.            }   
33.        }.start();   
34.        PhantomReference abcWeakRef = new PhantomReference(abc,   
35.                referenceQueue);   
36.        abc = null;   
37.        Thread.currentThread().sleep(3000);   
38.        System.gc();   
39.        Thread.currentThread().sleep(3000);   
40.        isRun = false;   
41.    }   
42.   
43.} 
结果为
class java.lang.String@96354   
gc will collect:class java.lang.String@96354 

你可能感兴趣的:(Java关键字)