Java四大引用詳解:強引用、軟引用、弱引用、虛引用
面試官考察Java引用會問到強引用、弱引用、軟引用、虛引用,具體有什麼區別?本篇單獨來詳解 @
Java引用
從JDK 1.2版本開始,物件的引用被劃分為4種級別,從而使程式能更加靈活地控制物件的生命週期,這4種級別由高到低依次為:強引用、軟引用、弱引用和虛引用。
強引用
強引用是最普遍的引用,一般把一個物件賦給一個引用變數,這個引用變數就是強引用。
比如:
// 強引用 MikeChen mikechen=new MikeChen();
在一個方法的內部有一個強引用,這個引用儲存在Java棧中,而真正的引用內容(MikeChen)儲存在Java堆中。
如果一個物件具有強引用,垃圾回收器不會回收該物件,當記憶體空間不足時,JVM 寧願丟擲 OutOfMemoryError異常。
如果強引用物件不使用時,需要弱化從而使GC能夠回收,如下:
//幫助垃圾收集器回收此物件 mikechen=null;
顯式地設定mikechen物件為null,或讓其超出物件的生命週期範圍,則GC認為該物件不存在引用,這時就可以回收這個物件,具體什麼時候收集這要取決於GC演算法。
舉例:
package com.mikechen.java.refenence; /** * 強引用舉例 * * @author mikechen */ public class StrongRefenenceDemo { public static void main(String[] args) { Object o1 = new Object(); Object o2 = o1; o1 = null; System.gc(); System.out.println(o1); //null System.out.println(o2); //java.lang.Object@2503dbd3 } }
StrongRefenenceDemo 中儘管 o1已經被回收,但是 o2 強引用 o1,一直存在,所以不會被GC回收。
軟引用
軟引用是一種相對強引用弱化了一些的引用,需要用java.lang.ref.SoftReference 類來實現。
比如:
String str=new String("abc"); // 強引用 SoftReference<String> softRef=new SoftReference<String>(str); // 軟引用
如果一個物件只具有軟引用,則記憶體空間足夠,垃圾回收器就不會回收它,如果記憶體空間不足了,就會回收這些物件的記憶體。
先透過一個例子來了解一下軟引用:
/** * 弱引用舉例 * * @author mikechen */ Object obj = new Object(); SoftReference softRef = new SoftReference<Object>(obj);//刪除強引用 obj = null;//呼叫gc // 物件依然存在 System.gc();System.out.println("gc之後的值:" + softRef.get());
軟引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果軟引用所引用物件被垃圾回收,Java虛擬機器就會把這個軟引用加入到與之關聯的引用佇列中。
ReferenceQueue<Object> queue = new ReferenceQueue<>(); Object obj = new Object(); SoftReference softRef = new SoftReference<Object>(obj,queue);//刪除強引用 obj = null;//呼叫gc System.gc(); System.out.println("gc之後的值: " + softRef.get()); // 物件依然存在 //申請較大記憶體使記憶體空間使用率達到閾值,強迫gc byte[] bytes = new byte[100 * 1024 * 1024];//如果obj被回收,則軟引用會進入引用佇列 Reference<?> reference = queue.remove();if (reference != null){ System.out.println("物件已被回收: "+ reference.get()); // 物件為null }
軟引用通常用在對記憶體敏感的程式中,比如快取記憶體就有用到軟引用,記憶體夠用的時候就保留,不夠用就回收。
我們看下 Mybatis 快取類 SoftCache 用到的軟引用:
public Object getObject(Object key) { Object result = null; SoftReference<Object> softReference = (SoftReference)this.delegate.getObject(key); if (softReference != null) { result = softReference.get(); if (result == null) { this.delegate.removeObject(key); } else { synchronized(this.hardLinksToAvoidGarbageCollection) { this.hardLinksToAvoidGarbageCollection.addFirst(result); if (this.hardLinksToAvoidGarbageCollection.size() > this.numberOfHardLinks) { this.hardLinksToAvoidGarbageCollection.removeLast(); } } } } return result;}
注意:軟引用物件是在jvm記憶體不夠的時候才會被回收,我們呼叫System.gc()方法只是起通知作用,JVM什麼時候掃描回收物件是JVM自己的狀態決定的,就算掃描到軟引用物件也不一定會回收它,只有記憶體不夠的時候才會回收。
弱引用
弱引用的使用和軟引用類似,只是關鍵字變成了 WeakReference:
MikeChen mikechen = new MikeChen(); WeakReference<MikeChen> wr = new WeakReference<MikeChen>(mikechen );
弱引用的特點是不管記憶體是否足夠,只要發生 GC,都會被回收。
舉例說明:
package com.mikechen.java.refenence; import java.lang.ref.WeakReference; /** * 弱引用 * * @author mikechen */ public class WeakReferenceDemo { public static void main(String[] args) { Object o1 = new Object(); WeakReference<Object> w1 = new WeakReference<Object>(o1); System.out.println(o1); System.out.println(w1.get()); o1 = null; System.gc(); System.out.println(o1); System.out.println(w1.get()); } }
弱引用的應用
WeakHashMap
public class WeakHashMapDemo { public static void main(String[] args) throws InterruptedException { myHashMap(); myWeakHashMap(); } public static void myHashMap() { HashMap<String, String> map = new HashMap<String, String>(); String key = new String("k1"); String value = "v1"; map.put(key, value); System.out.println(map); key = null; System.gc(); System.out.println(map); } public static void myWeakHashMap() throws InterruptedException { WeakHashMap<String, String> map = new WeakHashMap<String, String>(); //String key = "weak"; // 剛開始寫成了上邊的程式碼 //思考一下,寫成上邊那樣會怎麼樣? 那可不是引用了 String key = new String("weak"); String value = "map"; map.put(key, value); System.out.println(map); //去掉強引用 key = null; System.gc(); Thread.sleep(1000); System.out.println(map); }}
當key只有弱引用時,GC發現後會自動清理鍵和值,作為簡單的快取表解決方案。
ThreadLocal
static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal<?>> { Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } //......}
ThreadLocal.ThreadLocalMap.Entry 繼承了弱引用,key為當前執行緒例項,和WeakHashMap基本相同。
虛引用
虛引用”顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用並不會決定物件的生命週期。如果一個物件僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。
虛引用也稱為“幽靈引用”或者“幻影引用”,它是最弱的一種引用關係。
虛引用需要java.lang.ref.PhantomReference 來實現:
A a = new A(); ReferenceQueue<A> rq = new ReferenceQueue<A>(); PhantomReference<A> prA = new PhantomReference<A>(a, rq);
虛引用主要用來跟蹤物件被垃圾回收器回收的活動。
虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用佇列 (ReferenceQueue)聯合使用,當垃圾回收器準備回收一個物件時,如果發現它還有虛引用,就會在回收物件的記憶體之前,把這個虛引用加入到與之 關聯的引用佇列中。
Java引用總結
java4種引用的級別由高到低依次為:強引用 > 軟引用 > 弱引用 > 虛引用。
以上
作者簡介
陳睿|mikechen,10年+大廠架構經驗,《BAT架構技術500期》系列文章作者,分享十餘年BAT架構經驗以及面試心得!
閱讀mikechen的網際網路架構更多技術文章合集
| | | | | | | 架構師
關注「mikechen 的網際網路架構」公眾號,回覆 【架構】領取我原創的《300 期 + BAT 架構技術系列與 1000 + 大廠面試題答案》
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70011997/viewspace-2910321/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java的強引用、軟引用、弱引用、虛引用Java
- Java四種引用包括強引用,軟引用,弱引用,虛引用。Java
- 理解Java的強引用、軟引用、弱引用和虛引用Java
- Java/Android中的強引用、軟引用、弱引用、虛引用JavaAndroid
- Java中的四種引用方式(強引用、軟引用、弱引用、虛引用)Java
- 【JVM】如何理解強引用、軟引用、弱引用、虛引用?JVM
- java的強引用、軟引用、弱引用、幻象引用,引用佇列總結Java佇列
- Java常見知識點彙總(⑲)——Java中的強引用、弱引用、軟引用、虛引用Java
- Java引用型別解析:掌握強引用、軟引用、弱引用和幻象引用的妙用Java型別
- 強引用、軟引用、弱引用、幻象引用有什麼區別?
- 強引用、軟引用、弱引用、幻象引用再不理解就晚了
- Java中強、軟、弱、虛四種引用詳解Java
- Java中的弱引用詳解Java
- 有效避免OOM--合理使用軟引用和弱引用OOM
- Java中的弱引用Java
- Java弱引用與WeakHashMapJavaHashMap
- Android效能優化篇:使用軟引用和弱引用Android優化
- Java 如何有效地避免OOM:善於利用軟引用和弱引用JavaOOM
- Android開發優化之——使用軟引用和弱引用Android優化
- python3學習筆記之 強引用和弱引用Python筆記
- 理解Java中的弱引用Java
- java四大引用總結Java
- Java中的方法引用詳解Java
- Swift中的迴圈強引用 【使用無主引用解決】Swift
- 詳解C++引用C++
- Git Reference引用詳解Git
- Swift 4 弱引用實現Swift
- Python 弱引用 學習Python
- 什麼是java四大引用?Java
- java的四大引用型別Java型別
- Android效能優化之巧用軟引用與弱引用優化記憶體使用Android優化記憶體
- JVM 符號引用和直接引用JVM符號
- Java中的引用Java
- 從原始碼解析 Swift 弱引用原始碼Swift
- weak 弱引用的實現方式
- JVM - 引用JVM
- PHP 引用PHP
- 方法引用