1. 程式人生 > >java中引用的概念

java中引用的概念

強引用(StrongReference)

強引用就是指在程式程式碼之中普遍存在的,比如下面這段程式碼中的object和str都是強引用:

1 2 Object object = new  Object(); String str = "hello" ;

只要某個物件有強引用與之關聯,JVM必定不會回收這個物件,即使在記憶體不足的情況下,JVM寧願丟擲OutOfMemory錯誤也不會回收這種物件。比如下面這段程式碼:

1 2 3 4 5 6 7 8 9 10 public  class  Main {      public  static  void  main(String[] args) {          new
  Main().fun1();      }             public  void  fun1() {          Object object = new  Object();          Object[] objArr = new  Object[ 1000 ];      } }

當執行至Object[] objArr = new Object[1000];這句時,如果記憶體不足,JVM會丟擲OOM錯誤也不會回收object指向的物件。不過要注意的是,當fun1執行完之後,object和objArr都已經不存在了,所以它們指向的物件都會被JVM回收。

如果想中斷強引用和某個物件之間的關聯,可以顯示地將引用賦值為null,這樣一來的話,JVM在合適的時間就會回收該物件。

軟引用(SoftReference)

軟引用是用來描述一些有用但並不是必需的物件,在Java中用java.lang.ref.SoftReference類來表示。對於軟引用關聯著的物件,只有在記憶體不足的時候JVM才會回收該物件。因此,這一點可以很好地用來解決OOM的問題,並且這個特性很適合用來實現快取:比如網頁快取、圖片快取等。

軟引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果軟引用所引用的物件被JVM回收,這個軟引用就會被加入到與之關聯的引用佇列中。下面是一個使用示例:

1 2 3 4 5 6 7 8 9 10 11 12 import  java.lang.ref.WeakReference;    public  class  Main {      public  static  void  main(String[] args) {                 SoftReference<String> sr = new  SoftReference<String>( new  String( "hello" ));                     System.out.println(sr.get());          System.gc();                //通知JVM的gc進行垃圾回收          System.out.println(sr.get());      } }

弱引用(WeakReference)

弱引用也是用來描述非必需物件的,當JVM進行垃圾回收時,無論記憶體是否充足,都會回收被弱引用關聯的物件。在java中,用java.lang.ref.WeakReference類來表示。下面是使用示例:

1 2 3 4 5 6 7 8 9 10 11 12 import  java.lang.ref.WeakReference;    public  class  Main {      public  static  void  main(String[] args) {                 WeakReference<String> sr = new  WeakReference<String>( new  String( "hello" ));                     System.out.println(sr.get());          System.gc();                //通知JVM的gc進行垃圾回收          System.out.println(sr.get());      } }

虛引用(PhantomReference)

虛引用和前面的軟引用、弱引用不同,它並不影響物件的生命週期。在java中用java.lang.ref.PhantomReference類表示。如果一個物件與虛引用關聯,則跟沒有引用與之關聯一樣,在任何時候都可能被垃圾回收器回收。

要注意的是,虛引用必須和引用佇列關聯使用,當垃圾回收器準備回收一個物件時,如果發現它還有虛引用,就會把這個虛引用加入到與之 關聯的引用佇列中。程式可以通過判斷引用佇列中是否已經加入了虛引用,來了解被引用的物件是否將要被垃圾回收。如果程式發現某個虛引用已經被加入到引用佇列,那麼就可以在所引用的物件的記憶體被回收之前採取必要的行動。虛引用與軟引用和弱引用不同的是虛引用是在引用物件gc前加入佇列,所以可以在這一段時間對引用物件進行清理操作。

進一步理解軟引用和弱引用

對於強引用,我們平時在編寫程式碼時經常會用到。而對於其他三種類型的引用,使用得最多的就是軟引用和弱引用,這2種既有相似之處又有區別。它們都是用來描述非必需物件的,但是被軟引用關聯的物件只有在記憶體不足時才會被回收,而被弱引用關聯的物件在JVM進行垃圾回收時總會被回收。針對上面的特性,軟引用適合用來進行快取,當記憶體不夠時能讓JVM回收記憶體,弱引用能用來在回撥函式中防止記憶體洩露。因為回撥函式往往是匿名內部類,隱式儲存有對外部類的引用,所以如果回撥函式是在另一個執行緒裡面被回撥,而這時如果需要回收外部類,那麼就會記憶體洩露,因為匿名內部類儲存有對外部類的強引用。

  public static boolean isRun = true;

    @SuppressWarnings("static-access")
    public static void main(String[] args) throws Exception {
        String abc = new String("abc");
        System.out.println(abc.getClass() + "@" + abc.hashCode());
        final ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();
        new Thread() {
            public void run() {
                while (isRun) {
                    Object obj = referenceQueue.poll();
                    if (obj != null) {
                        try {
                            Field rereferent = Reference.class
                                    .getDeclaredField("referent");
                            rereferent.setAccessible(true);
                            Object result = rereferent.get(obj);
                            System.out.println(obj);
                            System.out.println("gc will collect:"
                                    + result.getClass() + "@"
                                    + result.hashCode() + "\t"
                                    + (String) result);
                        } 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;
    }}