JVM 四種引用
1. 前言
延續(xù)上節(jié)可達性分析法的講解,本節(jié)主要講解可達性分析法所使用的四種引用類型,本節(jié)主要內容如下:
- 強引用的定義以及如何消除強引用,為本節(jié)重點內容之一;
- 軟引用的定義及使用場景,為本節(jié)重點內容之一;
- 弱引用的定義及代碼示例,驗證任何情況下,只要發(fā)生 GC 就會回收弱引用對象,為本節(jié)重點內容之一;
- 虛引用的定義以及作用,為本節(jié)重點內容之一;
2. 可達性分析的四種引用類型
上節(jié)課程內容講解了可達性分析,可達性分析的 GC Roots 均為引用對象,那么引用對象有 4 種引用類型如下:
- 強引用;
- 軟引用;
- 弱引用;
- 虛引用。
本節(jié)課程內容與可達性分析相輔相成,學習者務必在學習完可達性分析內容后再學習本節(jié)內容。
3. 強引用
定義:強引用就是指在程序代碼之中普遍存在的,類似Object obj = new Object()
這類的引用,只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象。當內存空間不足,Java 虛擬機寧愿拋出 OutOfMemoryError 錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足的問題。
代碼示例:
public class DemoTest {
public static void main(String[] args) {
Object obj = new Object(); // 強引用
}
}
在強引用的定義中有這樣一句話:“只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象?!?那么有沒有辦法將強引用消除呢?
消除強引用示例代碼:
public class DemoTest {
public static void main(String[] args) {
Object obj = new Object(); // 強引用
obj = null; //消除強引用
}
}
如果不使用強引用時,可以賦值 obj=null
,顯示的設置 obj 為 null,則 gc 認為該對象不存在引用,這時候就可以回收此對象。
4. 軟引用
定義:軟引用用來描述一些還有用,但并非必需的對象。對于軟引用關聯(lián)著的對象,如果內存充足,則垃圾回收器不會回收該對象,如果內存不夠了,就會回收這些對象的內存。
在 JDK 1.2 之后,提供了 SoftReference 類來實現(xiàn)軟引用。軟引用可用來實現(xiàn)內存敏感的高速緩存。軟引用可以和一個引用隊列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯(lián)的引用隊列中。
軟引用使用場景:Android 應用圖片
軟引用主要應用于內存敏感的高速緩存,在 Android 系統(tǒng)中經(jīng)常使用到。一般情況下,Android 應用會用到大量的默認圖片,這些圖片很多地方會用到。如果每次都去讀取圖片,由于讀取文件需要硬件操作,速度較慢,會導致性能較低。所以我們考慮將圖片緩存起來,需要的時候直接從內存中讀取。
但是,由于圖片占用內存空間比較大,緩存很多圖片需要很多的內存,就可能比較容易發(fā)生 OutOfMemory 異常。這時,我們可以考慮使用軟引用技術來避免這個問題發(fā)生。
SoftReference 可以解決 OOM 的問題,每一個對象通過軟引用進行實例化,這個對象就以cache的形式保存起來,當再次調用這個對象時,那么直接通過軟引用中的 get() 方法,就可以得到對象中的資源數(shù)據(jù),這樣就沒必要再次進行讀取了,直接從 cache 中就可以讀取得到,當內存將要發(fā)生 OOM 的時候,GC 會迅速把所有的軟引用清除,防止 OOM 發(fā)生。
5. 弱引用
定義:弱引用描述非必需對象。被弱引用關聯(lián)的對象只能生存到下一次垃圾回收之前,垃圾收集器工作之后,無論當前內存是否足夠,都會回收掉只被弱引用關聯(lián)的對象。Java 中的類 WeakReference 表示弱引用。
代碼示例:
import java.lang.ref.WeakReference;
public class Main {
public static void main(String[] args) {
WeakReference<String> sr = new WeakReference<String>(new String("hello"));
System.out.println(sr.get());
System.gc(); //通知JVM的gc進行垃圾回收
System.out.println(sr.get());
}
}
結果驗證:第二個輸出結果是 null,這說明只要 JVM 進行垃圾回收,被弱引用關聯(lián)的對象必定會被回收掉。
hello
null
6. 虛引用
定義:"虛引用"顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用并不會決定對象的生命周期。如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收。虛引用在 Java 中使用 java.lang.ref.PhantomReference
類表示。
作用:虛引用主要用來跟蹤對象被垃圾回收的活動。
虛引用與軟引用和弱引用的區(qū)別:虛引用必須和引用隊列(ReferenceQueue)聯(lián)合使用。當垃圾回收器準備回收一個對象時,如果發(fā)現(xiàn)它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之關聯(lián)的引用隊列中。程序可以通過判斷引用隊列中是否已經(jīng)加入了虛引用,來了解被引用的對象是否將要被垃圾回收。程序如果發(fā)現(xiàn)某個虛引用已經(jīng)被加入到引用隊列,那么就可以在所引用的對象的內存被回收之前采取必要的行動。
使用示例:虛引用必須和引用隊列(ReferenceQueue)聯(lián)合使用
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
public class Main {
public static void main(String[] args) {
ReferenceQueue<String> queue = new ReferenceQueue<String>();
PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue);
System.out.println(pr.get());
}
}
7. 小結
本節(jié)主要講解可達性分析的四種對象引用類型,通篇皆為重點內容,需要學習者理解并掌握這四種引用類型。