在Java語言中,除了基本數據類型外,其他的都是指向各類對象的對象引用;Java中根據其生命周期的長短,將引用分為4類。
不同的引用類型,主要體現的是對象不同的可達性狀態和對垃圾收集的影響。
1 、強引用
我們平常典型編碼Object obj = new Object()中的obj就是強引用。通過關鍵字new創建的對象所關聯的引用就是強引用。
當JVM內存空間不足,JVM寧願拋出OutOfMemoryError運行時錯誤(OOM),使程序異常終止,也不會靠隨意回收具有強引用的“存活”對象來解決內存不足的問題。
對於一個普通的對象,如果沒有其他的引用關系,只要超過了引用的作用域或者顯式地將相應強引用賦值為 null,就是可以被垃圾收集的了,具體回收時機還是要看垃圾收集策略。
2 、軟引用
軟引用通過SoftReference類實現。 軟引用的生命周期比強引用短一些。
只有當 JVM 認為內存不足時,才會去試圖回收軟引用指向的對象,即JVM 會確保在拋出 OutOfMemoryError 之前,清理軟引用指向的對象。
軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。
后續,我們可以調用ReferenceQueue的poll()方法來檢查是否有它所關心的對象被回收。如果隊列為空,將返回一個null,否則該方法返回隊列中前面的一個Reference對象。
應用場景:軟引用通常用來實現內存敏感的緩存。如果還有空閑內存,就可以暫時保留緩存,當內存不足時清理掉,這樣就保證了使用緩存的同時,不會耗盡內存。
3、弱引用
弱引用通過WeakReference類實現。 弱引用的生命周期比軟引用短。
不管當前內存空間足夠與否,都會回收它的內存。由於垃圾回收器是一個優先級很低的線程,因此不一定會很快回收弱引用的對象。
弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列
/** * 弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中 */ public class ReferenceQueueDemo { public static void main(String[] args) throws InterruptedException { Object object1 = new Object(); ReferenceQueue referenceQueue = new ReferenceQueue(); WeakReference<Object> weakReference = new WeakReference<>(object1,referenceQueue); System.out.println(object1); System.out.println(weakReference.get()); System.out.println(referenceQueue.poll()); System.out.println("====================="); object1 = null; System.gc(); TimeUnit.SECONDS.sleep(1); System.out.println(object1); System.out.println(weakReference.get()); System.out.println(referenceQueue.poll()); } }
應用場景:弱應用同樣可用於內存敏感的緩存。
4 虛引用
虛引用也叫幻象引用,通過PhantomReference類來實現。
如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。
無法通過虛引用訪問對象的任何屬性或函數。僅僅是提供了一種確保對象被 finalize 以后,做某些事情的機制。
虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器准備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之關聯的引用隊列中。
ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);
程序可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。
如果程序發現某個虛引用已經被加入到引用隊列,那么就可以在所引用的對象的內存被回收之前采取一些程序行動。
應用場景:可用來跟蹤對象被垃圾回收器回收的活動,當一個虛引用關聯的對象被垃圾收集器回收之前會收到一條系統通知。
public class PhantomReferenceDemo { public static void main(String[] args) throws InterruptedException { Object object1 = new Object(); ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>(); PhantomReference<Object> phantomReference = new PhantomReference<>(object1,referenceQueue); System.out.println(object1); System.out.println(phantomReference.get()); System.out.println(referenceQueue.poll()); System.out.println("====================="); object1 = null; System.gc(); TimeUnit.SECONDS.sleep(1); System.out.println(object1); System.out.println(phantomReference.get()); System.out.println(referenceQueue.poll()); } }