2019獨角獸企業重金招聘Python工程師標準>>>
1. 引用類型劃分
-
強引用:當內存不足時,JVM寧可出現“OutOfMemoryError”錯誤停止,也需要進行保存,并且不會將此空間回收。
-
軟引用:當內存不足的時候,進行對象的回收處理,往往用于高速緩存中。
-
弱引用:不管內存是否緊張,只要有垃圾產生,立即回收。
-
幽靈引用(虛引用):和沒有引用是一樣的。
2. 強引用
1. 簡單介紹
- 強引用是JVM默認的支持模式,即:在引用的期間內,如果該堆內存被指定的棧內存有聯系,那么該對象就無法被GC所回收,而一旦出現內存空間不足,就會出現“OutOfMemoryError”。
2. 范例:觀察強引用
-
測試代碼
public class TestDemo {public static void main(String[] args) {Object obj = new Object(); // 強引用,默認的支持Object ref = obj; // 引用傳遞obj = null; // 斷開了一個連接System.gc();System.out.println(ref);} }
-
終端命令
> javac TestDemo.java > java TestDemo
-
結果
java.lang.Object@15db9742
-
結論
- 此時如果對象堆內存有棧內存的指向,那么該對象將無法被GC回收。
- 強引用是我們一直在使用的模式,并且也是以后的開發中主要的使用模式,因為強引用有這樣的內存分配異常問題,所以開發原則是盡量少實例化對象。
3. 軟引用
1. 簡單介紹
-
在很多的開源組件之中,往往會使用軟引用作為緩存組件出現,其最大的特點:內存不足時回收,充足時不回收。
-
想實現軟引用需要單獨的一個類來實現控制:java.lang.ref.SoftReference
2. 范例:觀察軟引用
-
測試代碼:
import java.lang.ref.SoftReference;public class TestDemo {public static void main(String[] args) {Object obj = new Object();SoftReference<Object> ref = new SoftReference<Object>(obj); // 軟引用obj = null; // 斷開連接System.gc();System.out.println(ref.get());} }
-
終端命令
> javac TestDemo.java > java TestDemo
-
結果
java.lang.Object@15db9742
-
結論
- 軟引用在內存不緊張的情況下不會被回收。
3. 范例:觀察內存緊張情況下的軟引用
-
測試代碼
import java.lang.ref.SoftReference;public class TestDemo {public static void main(String[] args) {Object obj = new Object();String str = "hello world !!!";SoftReference<Object> ref = new SoftReference<Object>(obj);obj = null;try {for (int i = 0; i < 10000; i++) {str += str;str.intern();}} catch (Throwable e) {}System.gc();System.out.println(ref.get());} }
-
終端命令
> javac TestDemo.java > java -Xmx10m -Xms10m TestDemo
-
結果
null
-
結論
- 軟引用在內存緊張的情況下會被回收。
4. 弱引用
1. 簡單介紹
- 弱引用,只要一進行gc處理,那么所引用的對象將會立即被回收。弱引用需要使用的是Map接口的子類:java.util.WeakHashMap。
2. 范例:觀察弱引用
-
測試代碼
import java.lang.ref.SoftReference; import java.util.Map; import java.util.WeakHashMap;public class TestDemo {public static void main(String[] args) {String key = new String("shadowolf");String value = new String("www.shadowolf.cn");Map<String, String> map = new WeakHashMap<String, String>();map.put(key, value);System.out.println(map);key = null;System.out.println(map);System.gc();System.out.println(map);} }
-
終端命令
> javac TestDemo.java > java TestDemo
-
結果
{shadowolf=www.shadowolf.cn} {shadowolf=www.shadowolf.cn} {}
-
結論
- 一旦出現GC,則必須進行回收處理,并且一回收一個準。
3. 范例:觀察 java.lang.ref.WeakReference
-
測試代碼
import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.Map; import java.util.WeakHashMap;public class TestDemo {public static void main(String[] args) {String key = new String("shadowolf");WeakReference<String> ref = new WeakReference<String>(key);System.out.println(ref.get());key = null;System.out.println(ref.get());System.gc();System.out.println(ref.get());} }
-
終端命令
> javac TestDemo.java > java TestDemo
-
結果
shadowolf shadowolf null
5. 引用隊列
1. 簡單介紹
- 引用隊列保存那些準備被回收的對象。很多時候所有的對象的回收掃描都是從根對象開始的,那么對于整個GC而言,如果要想確定哪些對象可以被回收,就必須確定好引用的強度,這個也就是所謂的引用路徑的設置。
2. 引用隊列的操作流程
-
單條引用路徑的可及性判斷:在這條路徑上,最弱的一個引用決定對象的可及性。
-
多條引用路徑的可及性判斷:在這幾條路徑上,最強的一個引用決定對象的可及性。
-
例如:如果要找到對象5,那么1找到5屬于“強 + 軟”,2找到5屬于“強 + 弱”。軟引用比弱引用保存的強。所以這個時候對于對象的引用而言,如果要進行引用關聯的判斷,那么就必須找到強關聯,為了避免非強引用對象所帶來的內存引用問題,所以提供引用隊列的概念。如果在創建一個軟引用或弱引用對象使用了引用隊列的方式,那么這個對象在回收之后會自動保存到引用隊列之中。
3. 范例:使用引用隊列
-
測試代碼
import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference;public class TestDemo {public static void main(String[] args) throws Exception {Object obj = new Object();ReferenceQueue<Object> queue = new ReferenceQueue<Object>();WeakReference<Object> ref =new WeakReference<Object>(obj, queue);System.out.println(queue.poll());obj = null;System.gc();Thread.sleep(100); // 保存引用隊列需要點時間System.out.println(queue.poll());} }
-
終端命令
> javac TestDemo.java > java TestDemo
-
結果
null java.lang.ref.WeakReference@15db9742
-
結論
- 被回收的弱引用對象被保存到了引用隊列中。
- 引用隊列主要做一些被回收對象的控制。
6. 幽靈引用(虛引用)
1. 簡單介紹
- 永遠取得不了的數據就叫幽靈引用。
2. 范例:觀察幽靈引用
-
測試代碼
import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue;public class TestDemo {public static void main(String[] args) throws Exception {Object obj = new Object();ReferenceQueue<Object> queue = new ReferenceQueue<Object>();PhantomReference<Object> ref = new PhantomReference<Object>(obj, queue);System.gc();System.out.println(ref.get());System.out.println(queue.poll());} }
-
終端命令
> javac TestDemo.java > java TestDemo
-
結果
null null
-
結論
- 所有保存在幽靈引用類型中的數據都不會真正的保留。