1. 程式人生 > >jvm 07-java引用型別

jvm 07-java引用型別

java引用型別

  • 強引用:當記憶體不足的時候,都不會進行空間回收,最終JVM丟擲OutOfMemoryError
  • 軟引用:當記憶體不足的時候,進行物件的回收處理,往往用於快取記憶體中
  • 弱引用:不管記憶體是否緊張,只要GC執行都會回收
  • 幽靈引用:和沒引用一樣。

強引用

  • JVM預設支援模式
  • 在引用期間內,如果該堆記憶體被指定的棧記憶體有聯絡,那該物件就無法被GC所回收
  • 一旦出現記憶體不足,就會出現OutOfMemoryError異常
  • 正因為強引用具備記憶體分配異常問題,因此儘量少例項化物件

測試程式:

package cn.liang.jvm;
import static org.hamcrest.CoreMatchers.nullValue;
import java.lang.ref.SoftReference;
public class referenceType2 {
  public static void main(String[] args) {
      Object object = new Object();
      Object ref = object;
      object = null;
      System.out.println("記憶體充足時進行gc回收:");
      System.gc();
      System.out.println(ref);
      System.out.println("記憶體不足時進行gc回收:");
      try {
          String string = "liangjingfu";
          while (true) {
              string += string + string;
              string.intern();    
          }
      } catch (Throwable e) {
      }
      System.out.println(ref);
  }
}

輸出結果:

記憶體充足時進行gc回收:
[email protected]
記憶體不足時進行gc回收:
[email protected]

軟引用

  • 在許多的開源元件中,往往會使用軟引用作為快取元件出現
  • 軟引用不足時回收,不充足時不回收
  • 軟引用需要一個單獨的類來實現控制:java.lang.ref.SoftReference
    • 建構函式:public SoftReference(T referent)
    • 取出資料:public T get();

測試程式:

package cn.liang.jvm;
import static org.hamcrest.CoreMatchers.nullValue;
import java.lang.ref.SoftReference;
public class referenceType2 {
  public static void main(String[] args) {
      Object object = new Object();
      SoftReference<Object> ref = new SoftReference<Object>(object);
      object = null;
      System.out.println("記憶體充足時進行gc回收:");
      System.gc();
      System.out.println(ref.get());
      System.out.println("記憶體不足時進行gc回收:");
      try {
          String string = "liangjingfu";
          while (true) {
              string += string + string;
              string.intern();    
          }
      } catch (Throwable e) {
      }
      System.out.println(ref.get());
  }
}

輸出結果:

記憶體充足時進行gc回收:
[email protected]
記憶體不足時進行gc回收:
null

弱引用:

  • 只要一進行GC處理,那麼所引用的物件將會立即回收
  • 弱引用需要使用Map介面的子類:java.util.WeakHashMap
  • java.lang.ref包中存在一個WeakReference子類

測試程式1:

package cn.liang.jvm;
import java.util.Map;
import java.util.WeakHashMap;
public class referenceType3 {
  public static void main(String[] args) {
      String keyString = new String("name");
      String valueString = new String("liang");
      Map<String, String> map = new WeakHashMap<String, String>();
      map.put(keyString, valueString);
      keyString = null;
      System.out.println("記憶體進行gc回收前:");
      System.out.println(map);
      System.out.println("記憶體進行gc回收後:");
      System.gc();
      System.out.println(map);
  }
}

輸出結果:

記憶體進行gc回收前:
{name=liang}
記憶體進行gc回收後:
{}

測試程式2:

package cn.liang.jvm;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.WeakHashMap;
public class referenceType3 {
  public static void main(String[] args) {
      String keyString = new String("liang");
      WeakReference<String> reference = new WeakReference<String>(keyString);
      keyString = null;
      System.out.println("記憶體進行gc回收前:");
      System.out.println(reference.get());
      System.gc();
      System.out.println("記憶體進行gc回收後:");
      System.out.println(reference.get());
  }
}

輸出結果:

記憶體進行gc回收前:
liang
記憶體進行gc回收後:
null

引用佇列

  • 主要是儲存那些準備被回收的物件
  • 所有的物件的回收掃描都是從根物件開始的
  • 引用路徑的設定即確定好哪些物件可以被回收後,設定相應的引用強度
  • 引用佇列可避免非強引用物件所帶來的記憶體引用問題,該物件被回收後會自動儲存

  • 找到物件5有兩個路徑:
    • 物件1 --> 物件5(強 + 軟)
    • 物件2 --> 物件5(強 + 弱)

測試程式:

package cn.liang.jvm;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.WeakHashMap;
public class referenceType4 {

  public static void main(String[] args) throws Exception {
      Object obj = new Object();
      ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
      WeakReference<Object> reference = new WeakReference<Object>(obj,queue);
      System.out.println("記憶體進行gc回收前:");
      System.out.println(queue.poll());
      obj = null;
      System.gc();
      Thread.sleep(100);
      System.out.println("記憶體進行gc回收後,物件儲存:");
      System.out.println(queue.poll());
  }
}

輸出結果:

記憶體進行gc回收前:
null
記憶體進行gc回收後,物件儲存:
[email protected]

幽靈引用

  • 永遠取不了的資料

測試程式:

package cn.liang.jvm;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.WeakHashMap;
public class referenceType5 {
  public static void main(String[] args) throws Exception {
      Object obj = new Object();
      ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
      PhantomReference<Object> reference = new PhantomReference<Object>(obj,queue);
      System.gc();
      System.out.println("物件讀取:");
      System.out.println(reference.get());
      System.out.println("物件儲存後讀取:");
      System.out.println(queue.poll());
  }
}

輸出結果:

物件讀取:
null
物件儲存後讀取:
null