Java引入類型
強引用:當內存不足的時候,JVM寧可出現OutOfMemoryError,也不會將內存回收。
強引用是JVM默認的支持模式,即:在引用期間,如果該堆內存被棧內存所指向,那麼該對象無法被GC回收,如果出現內存空間不足,就會拋出 “OutOfMemoryError”。
public static void main(String[] args) { Object o = new Object(); // 強引用 Object ref = o; // 引用傳遞 o = null; // 斷開一個引用 System.gc(); // 手動垃圾回收 System.out.println(ref); } 輸出: java.lang.Object@3cd1a2f1
軟引用:內存不足的時候,進行對象的回收,往往用於高速緩存。
在許多的開源組件之中,往往會使用軟引用作爲緩存組件出現,最大的特點就是:內存空間充足時不回收,內存空間不足時回收。
// 內存充足 public static void main(String[] args) { Object o = new Object(); SoftReference softReference = new SoftReference(o); // 軟引用 o = null; // 使new Object() 只維護一個軟引用 System.gc(); // 垃圾回收 System.out.println("軟引用:" + softReference.get()); } 輸出: 軟引用:java.lang.Object@3cd1a2f1 /******************************************************/ // 內存不足 public static void main(String[] args) { Object o = new Object(); SoftReference softReference = new SoftReference(o); // 軟引用 o = null; // 使new Object() 只維護一個軟引用 // 創造大量垃圾,觸發GC String str = "showSoftRef"; try { for (int i = 0; i < 100; i++) { str += str; str.intern(); } } catch (Throwable e) { } System.out.println("軟引用:" + softReference.get()); } 輸出: 軟引用:null
弱引用:不管內存是否緊張,只要有GC處理,就會被回收。弱引用需要使用的是Map接口的子類:java.util.WeakHashMap。
public static void main(String[] args) { String hello = new String("hello"); String world = new String("world"); // 弱引用 Map<String, String> map = new WeakHashMap<String, String>(); map.put(hello, world); System.out.println(map); hello = null; //斷開強引用 System.out.println(map); System.gc(); // 垃圾回收 System.out.println(map); } 輸出: {hello=world} {hello=world} {} /******************************************************/ 把上面的WeakHashMap替換成HashMap,輸出結果爲: {hello=world} {hello=world} {hello=world} // 因爲:HashMap是強引用,不會被回收 // 爲什麼項目中不用WeakHashMap而頻繁使用HashMap呢? // 如果在項目中使用WeakHashMap,當一條線程在取數據的時候,另外一條線程在進行GC,這個容易丟失數據。 /******************************************************/ public static void main(String[] args) { Object o = new Object(); WeakReference softReference = new WeakReference(o); // 弱引用 o = null; // 使new Object() 只維護一個弱引用 System.gc(); // 垃圾回收 System.out.println("弱引用:" + softReference.get()); } 輸出: 弱引用:null
幽靈引用(虛引用):永遠無法從這個引用中取數據。
所有保存在幽靈引用中的數據都不會真正的保留。
public static void main(String[] args) throws InterruptedException { Object o = new Object(); ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); PhantomReference softReference = new PhantomReference(o, queue); // 幽靈引用 // 這裏沒有斷開強引用 System.gc(); System.out.println(softReference.get()); System.out.println(queue.poll()); } 輸出: null null
引用對列:保存準備被回收的對象。很多時候對象的回收掃描都要從根集合開始,那麼對於整個GC而言,要想確定哪些對象可以被回收,就必須確定好引用的強度這個也就是所謂的引用路徑設置。
如果現在要找到對象5,很明顯:1 到 5 屬於 “強+軟”,2 到 5 屬於 “強+弱”;軟引用要比弱引用保存程度更強。這個時候對於對象的引用而言,如果要進行引用的關聯判斷,我們就必須找到強關聯。爲了避免非強引用對象帶來的內存引用問題,所以提供引用隊列的概念。
如果在創建軟引用或者弱引用類型的時候使用引用隊列的方式,那麼這個對象被回收之後會自動保存在引用隊列之中。
public static void main(String[] args) throws InterruptedException { Object o = new Object(); ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); // 引用隊列 WeakReference softReference = new WeakReference(o, queue); // 弱引用 System.out.println(queue.poll()); o = null; // 斷開強引用 System.gc(); Thread.sleep(100); // 等待對象被保存到引用隊列中 System.out.println(queue.poll()); } 輸出: null java.lang.ref.WeakReference@3cd1a2f1