JVM - 引用

wavesZh發表於2018-11-25

1. 引言

JVM如何判斷物件是否“死去”以便進行GC回收,目前有兩種演算法:引用計算演算法(物件的引用數量),可達性分析演算法(引用鏈是否可達)。這兩種演算法都與引用有關,那便要了解下引用是個什麼東西。

2. 引用的型別

2.1 強引用(Strong Reference)

2.1.1 概念

Object object  = new Obejct();
String s = "hello";
複製程式碼

強引用使得被引用物件不容易被GC: 只要強引用存在,垃圾收集器永遠不會回收掉被引用的物件。 即使在記憶體不足的情況下,JVM即使丟擲OutOfMemoryError異常也不會回收這種物件

2.2 軟引用(Soft Reference)

2.2.1 概念

SoftReference<StringBuilder> softBuilder = new SoftReference<StringBuilder>(builder);
複製程式碼

軟引用用來描述一些還有用但是非必需的物件。在系統即將發生記憶體溢位時,會將軟引用關聯的物件進行回收。如果這次回收還沒有足夠的記憶體,才會丟擲記憶體溢位異常。

2.2.2 使用場景

  • 只有在記憶體不足的時候JVM才會回收該物件這個特性很好解決了OOM的問題,並且也適合用於實現快取。
  • 引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果軟引用所引用的物件被垃圾回收器回收,Java虛擬機器就會把這個軟引用加入到與之關聯的引用佇列中。

2.3 弱引用(Weak Reference)

WeakReference<StringBuilder> weakBuilder = new WeakReference<StringBuilder>(builder);
複製程式碼

弱引用也是描述非必須物件,但其強度比軟引用更弱點。被其引用的物件只能生存到下一次垃圾收集發生之前,無論當前記憶體是否足夠

2.4 虛引用(Phanton Reference)

PhantomReference<StringBuilder> phantomBuilder = new PhantomReference<StringBuilder>(builder);
複製程式碼

虛引用也稱為幽靈引用或者幻影引用,是最弱的引用。一個物件是否有虛引用的存在不會影響其生存時間,也不能通過虛引用來獲取一個物件的例項。使用虛引用的唯一目的就是被引用物件在被收集器回收時可以收到一個系統通知。

3 如何判斷一個物件的可達性?

單挑引用鏈的可達性以最弱的一個引用型別來決定; 
多條引用鏈的可達性以最強的一個引用型別來決定;
複製程式碼
private void test_gc1(){
    //在heap中建立內容為"wohenhao"的物件,並建立a到該物件的強引用,此時該物件時強可及
    String a=new String("wohenhao");
    //對heap中的物件建立軟引用,此時heap中的物件仍然是強可及
    SoftReference< ?> softReference=new SoftReference<String>(a);
    //對heap中的物件建立弱引用,此時heap中的物件仍然是強可及
    WeakReference< ?> weakReference=new WeakReference<String>(a);
    System.out.println("強引用:"+a+"\n軟引用"+softReference.get()+"\n弱引用"+weakReference.get()+"\n");
    //heap中的物件從強可及到軟可及
    a=null;
    System.out.println("強引用:"+a+"\n軟引用"+softReference.get()+"\n弱引用"+weakReference.get()+"\n");
    softReference.clear();//heap中物件從軟可及變成弱可及,此時呼叫System.gc(),
    System.gc();
    System.out.println("強引用:"+a+"\n軟引用"+softReference.get()+"\n弱引用"+weakReference.get()+"\n");
}

private void test_gc2(){
//在heap中建立內容為"wohenhao"的物件,並建立a到該物件的強引用,此時該物件時強可及
    String a=new String("wohenhao");
    //對heap中的物件建立軟引用,此時heap中的物件仍然是強可及
    SoftReference< ?> softReference=new SoftReference<String>(a);
    //對heap中的物件建立弱引用,此時heap中的物件仍然是強可及
    WeakReference< ?> weakReference=new WeakReference<String>(a);
    System.out.println("強引用:"+a+"\n軟引用"+softReference.get()+"\n弱引用"+weakReference.get()+"\n");
    a=null;//heap中的物件從強可及到軟可及
    System.out.println("強引用:"+a+"\n軟引用"+softReference.get()+"\n弱引用"+weakReference.get()+"\n");
    System.gc();
    System.out.println("強引用:"+a+"\n軟引用"+softReference.get()+"\n弱引用"+weakReference.get()+"\n");
}
複製程式碼

參考文獻

  1. 徹底理解JVM常考題之分級引用模型
  2. 深入JVM物件引用

相關文章