強引用,軟引用,弱引用,幻象引用有什麼區別?
不同的引用類型,主要體現的是對象的不同的可達性(reachable)狀態和對垃圾收集的影響。
-
所謂強引用 (Strong Reference) 就是我們常見的普通對象引用,只要還有強引用指向一個對象,就能表明對象還活着,垃圾回收不回收這種對象。
-
軟引用,是一種相對強引用弱化一些的引用,只有當 JVM 認爲內存不足時,纔會試圖回收軟引用指向的對象。JVM 會確保在排除 OutOfMemoryError 之前,清理軟引用指向的對象,軟引用通常用來實現內存敏感的緩存,如果還有空閒內存,就可以暫時保留緩存,當內存不足時,清理掉,這樣就保證了使用緩存的同時,不會耗盡內存。
-
弱引用,比軟引用擁有更短的生命週期,在垃圾回收線程掃碼所管轄的內存區域的過程中,一大發現了只具有弱引用的對象,不管當前內存空間是否足夠,都會回收它的內存,由於垃圾回收器是一個優先級,因此不一定很快發現那些只有弱引用的對象。
-
虛引用,形同虛設 ,虛引用不會決定對象的生命週期,如果一個對象僅持有虛引用,其實就和沒有任何引用一樣。在任何時候都可能被垃圾回收器回收。
虛引用和軟引用的一個區別是,虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之關聯的引用隊列中。
四種引用類型對比
引用類型 | 被垃圾回收時間 | 用途 | 生存時間 |
---|---|---|---|
強引用 | 從來不會 | 對象的一般狀態 | JVM 停止運行時終止 |
軟引用 | 當內存不足時 | 對象緩存 | 內存不足時終止 |
弱引用 | 正常垃圾回收時 | 對象緩存 | 垃圾回收後終止 |
虛引用 | 正常垃圾回收時 | 跟蹤對象的垃圾回收 | 垃圾回收後終止 |
四種引用的應用場景
強引用
強引用是使用最普遍的引用,一般聲明如下:
Object strongReference = new Object();
如果要對強引用進行垃圾回收,需要設置強引用對象爲 null ,或者讓其超出對象的生命週期範圍,則認爲改對象不存在引用。
strongReference = null;
可以看下 ArrayList 是如何進行內存釋放的
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
軟引用
軟引用可用來實現內存敏感的高速緩存。
使用如下:
// 強引用
String strongReference = new String("abc");
// 軟引用
String str = new String("abc");
SoftReference<String> softReference = new SoftReference<String>(str);
軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。
ReferenceQueue refQueue = new ReferenceQueue();
SoftReference softRef = new SoftReference(obj, refQueue);
軟引用垃圾回收
if(JVM內存不足) {
// 將軟引用中的對象引用置爲null
str = null;
// 通知垃圾回收器進行回收
System.gc();
}
代表軟引用的類:java.lang.ref.SoftReference
代表弱引用的類:java.lang.ref.WeakReference
代表虛引用的類:java.lang.ref.PhantomReference
他們同時繼承了:java.lang.ref.Reference
public static void soft() throws Exception {
Object obj = new Object();
SoftReference<Object> softRef = new SoftReference<Object>(obj);
System.out.println(softRef.get()); //有時候會返回Null
// java.lang.Object@f9f9d8 System.out.println(refQueue.poll());
// null
// 清除強引用,觸發GC
obj = null;
//System.gc();
System.out.println(softRef.get());
//Thread.sleep(200);
//System.out.println(refQueue.poll());
}
弱引用
弱引用和軟引用的區別在於:弱引用擁有更短暫的生命週期,不管內存夠不夠,都會回收,都會回收它的內存。
Object obj = new Object();
WeakReference<Object> weakReference = new WeakReference<Object>(obj);
obj = null;
System.gc();
System.out.println(weakReference.get());// 有時候會返回Null
System.out.println(weakReference.isEnqueued());//判斷是否有垃圾回收標記,表示即將回收的垃圾
虛引用
// 虛引用
Object obj = new Object();
ReferenceQueue refQueue = new ReferenceQueue();
PhantomReference<Object> phantomReference = new PhantomReference<Object>(obj, refQueue);
System.out.println(phantomReference.get()); // 永遠返回Null
System.out.println(phantomReference.isEnqueued()); //返回時否從隊列中刪除
- 強可達(Strongly Reachable),就是當一個對象可以有一個或多個線程可以不通過各種引用訪問到的情況。比如,我們新創建一個對象,那麼創建它的線程對它就是強可達。
- 軟可達(Softly Reachable),就是當我們只能通過軟引用才能訪問到對象的狀態。
- 弱可達(Weakly Reachable),類似前面提到的,就是無法通過強引用或者軟引用訪問,只能通過弱引用訪問時的狀態。這是十分臨近fnalize狀態的時機,當弱引用被清除的時候,就符合finalize的條件了。
- 幻象可達(Phantom Reachable),上面流程圖已經很直觀了,就是沒有強、軟、弱引用關聯,並且finalize過了,只有幻象引用指向這個對象的時候。當然,還有一個最後的狀態,就是不可達(unreachable),意味着對象可以被清除了。
Java中4種引用的級別和強度由高到低依次爲:強引用 -> 軟引用 -> 弱引用 -> 虛引用