The NoteBook of EricKong

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            611 Posts :: 1 Stories :: 190 Comments :: 0 Trackbacks

          SoftReference、Weak Reference和PhantomRefrence分析和比較

            本文將談一下對SoftReference(軟引用)、WeakReference(弱引用)和PhantomRefrence(虛引用)的理解,這三個類是對heap中java對象的應用,通過這個三個類可以和gc做簡單的交互。

            強引用:

            除了上面提到的三個引用之外,還有一個引用,也就是最長用到的那就是強引用。例如:

          Object o=new Object();   
          Object o1=o;  

            上面代碼中第一句是在heap堆中創建新的Object對象通過o引用這個對象,第二句是通過o建立o1到new Object()這個heap堆中的對象的引用,這兩個引用都是強引用.只要存在對heap中對象的引用,gc就不會收集該對象.如果通過如下代碼:

          o=null;   
          o1=null;

            如果顯式地設置o和o1為null,或超出范圍,則gc認為該對象不存在引用,這時就可以收集它了??梢允占⒉坏扔诰鸵粫皇占?,什么時候收集這要取決于gc的算法,這要就帶來很多不確定性。例如你就想指定一個對象,希望下次gc運行時把它收集了,那就沒辦法了,有了其他的三種引用就可以做到了。其他三種引用在不妨礙gc收集的情況下,可以做簡單的交互。

            heap中對象有強可及對象、軟可及對象、弱可及對象、虛可及對象和不可到達對象。應用的強弱順序是強、軟、弱、和虛。對于對象是屬于哪種可及的對象,由他的最強的引用決定。如下:

          String abc=new String("abc");  //1   
          SoftReference<String> abcSoftRef=new SoftReference<String>(abc);  //2   
          WeakReference<String> abcWeakRef = new WeakReference<String>(abc); //3   
          abc=null; //4   
          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軟引用和弱引用可以有可無,但是虛引用必須有,參見:

          Reference(T paramT, ReferenceQueue<? super T>paramReferenceQueue)  

            被 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可能需要對此運用才能找到該弱可及對象。通過如下代碼可以了明了的看出它的作用:

          String abc=new String("abc");    
          WeakReference<String> abcWeakRef = new WeakReference<String>(abc);    
          abc=null;    
          System.out.println("before gc: "+abcWeakRef.get());    
          System.gc();    
          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")對象之前,你就可以做一些其他的事情。通過以下代碼可以了解他的作用。

          import java.lang.ref.PhantomReference;    
          import java.lang.ref.Reference;    
          import java.lang.ref.ReferenceQueue;    
          import java.lang.reflect.Field;    
             
          public class Test {    
              public static boolean isRun = true;    
             
              public static void main(String[] args) throws Exception {    
                  String abc = new String("abc");    
                  System.out.println(abc.getClass() + "@" + abc.hashCode());    
                  final ReferenceQueue referenceQueue = new ReferenceQueue<String>();    
                  new Thread() {    
                      public void run() {    
                          while (isRun) {    
                              Object o = referenceQueue.poll();    
                              if (o != null) {    
                                  try {    
                                      Field rereferent = Reference.class   
                                              .getDeclaredField("referent");    
                                      rereferent.setAccessible(true);    
                                      Object result = rereferent.get(o);    
                                      System.out.println("gc will collect:"   
                                              + result.getClass() + "@"   
                                              + result.hashCode());    
                                  } catch (Exception e) {    
             
                                      e.printStackTrace();    
                                  }    
                              }    
                          }    
                      }    
                  }.start();    
                  PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,    
                          referenceQueue);    
                  abc = null;    
                  Thread.currentThread().sleep(3000);    
                  System.gc();    
                  Thread.currentThread().sleep(3000);    
                  isRun = false;    
              }    
             
          }

            結果為:

            class java.lang.String@96354
            gc will collect:class java.lang.String@96354

          posted on 2014-03-21 17:01 Eric_jiang 閱讀(222) 評論(0)  編輯  收藏 所屬分類: Java
          主站蜘蛛池模板: 安平县| 日土县| 乌拉特中旗| 九龙县| 青冈县| 岗巴县| 永登县| 邵阳县| 陕西省| 沂南县| 郧西县| 登封市| 永定县| 象州县| 合山市| 郁南县| 岑溪市| 南靖县| 云梦县| 固镇县| 托克托县| 齐河县| 桂东县| 瑞昌市| 怀来县| 托克逊县| 阿克陶县| 胶南市| 甘德县| 邵阳市| 佳木斯市| 巴南区| 台东县| 东港市| 洪江市| 华亭县| 凤阳县| 忻城县| 小金县| 台山市| 锦屏县|