Java中弱引用指的是什么意思

小編給大家分享一下Java中弱引用指的是什么意思,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

10年積累的成都做網站、網站設計經驗,可以快速應對客戶對網站的新想法和需求。提供各種問題對應的解決方案。讓選擇我們的客戶得到更好、更有力的網絡服務。我雖然不認識你,你也不認識我。但先網站制作后付款的網站建設流程,更有稷山免費網站建設讓你可以放心的選擇與我們合作。

弱引用主要應用在不阻止它的key或者value 被回收的mapping。弱引用的出現就是為了垃圾回收服務的。它引用一個對象,但是并不阻止該對象被回收。如果使用一個強引用的話,只要該引用存在,那么被引用的對象是不能被回收的。弱引用則沒有這個問題。在垃圾回收器運行的時候,如果一個對象的所有引用都是弱引用的話,該對象會被回收。

弱引用案例深度解析

理想的情況下,我們希望當我們不再使用一個對象的時候,能夠在gc 發(fā)生的時候就把它回收掉。但是有些時候,由于我們的粗忽,在壞的情況下會導致內存溢出。這種案例尤其發(fā)生在一個生命使用周期很長的map 存放了很多實際使用生命周期短的對象。請看下面這個例子:

public class StrongRefenceDemo {
  static Map map;
  public static void main(String[] args) throws Exception {
  StrongRefenceDemo demo = new StrongRefenceDemo();
  demo.strongTest();
  System.out.println("gc 發(fā)生前:" + map.size());
  System.out.println("開始通知GC");
  //注意,這里只是通過垃圾回收器進行垃圾回收,并不一定馬上執(zhí)行
  System.gc();
  Thread.sleep(1000 * 5);
  System.out.println("gc 發(fā)生后:" + map.size());
  }
  /**
  * 強引用測試
  */
  public void strongTest() {
  map = new HashMap<>();
  String key = new String("key");
  String value = new String("value");
  map.put(key, value);
  key = null;
  value = null;
  }
  }

運行后輸出結果:

gc 發(fā)生前:1 開始通知GC gc 發(fā)生后:1

從輸出的結果可以看到,即使我們通過把key和value 設置為null 來告訴jvm,我們不再使用這個對象了,map 里面對象依然沒有被GC 回收,因為key和value 被一個強引用map 指向,根據可達性判斷,垃圾回收器是不能回收掉key和value 這個對象的。map 被定義為statis 的靜態(tài)變量,是一個使用生命周期很長的對象。在strongTest()方法中存在了一個key和value 的局部變量,它隨著方法的執(zhí)行完,這個變量的生命使用周期就結束了,但是粗糙的程序員忘記remove 了,這個時候垃圾回收器是不能回收它的。如果這種生命周期相對短的對象很多,最終就有可能消耗掉JVM中全部的內存。

但是這里我有一個好奇,假如這里的key和value 指向的對象在執(zhí)行完strongTest()方法 以后用不著了,但是我可能又不是很好的判斷去主動調用remove 來移除它。想要垃圾回收器自己判斷回收掉可不可以呢?答案其實是可以的,這個時候就是弱引用上場了,請看下面程序

public class WeakRefenceDemo {
  static Map, String> map;
  public static void main(String[] args) throws Exception {
  WeakRefenceDemo demo = new WeakRefenceDemo();
  demo.weakTest();
  System.out.println("gc 發(fā)生前:" + map.size());
  System.out.println("開始通知GC");
  //注意,這里只是通過垃圾回收器進行垃圾回收,并不一定馬上執(zhí)行
  System.gc();
  Thread.sleep(1000 * 5);
  System.out.println("gc 發(fā)生后:" + map.size());
  }
  /**
  * 若引用測試
  */
  public void weakTest() {
  map = new WeakHashMap<>();
  String key = new String("key");
  String value = new String("value");
  map.put(new WeakReference<>(key), value);
  key = null;
  value = null;
  }
  }

運行上面代碼輸出結果

gc 發(fā)生前:1 開始通知GC gc 發(fā)生后:0

從輸出結果0,我們可以判斷已經成功被垃圾回收了。what?整個過程我們只是把HashMap 換成了WeakHashMap,并且key 由String 換成了WeakReference。其實就是由于字符串只有弱引用指向,所以可以被垃圾回收掉。是不是很簡單,如果到這里你就停止研究弱引用了,那就太暴殄天物了

WeakHashMap 深度解析

上面的程序片段中,其實只有key 設置了為弱引用new WeakReference<>(key),那正常也就只有這個key 對應的內存被回收而已,由于沒有調用remove ,里面的value 和entry 也是不會回收掉的,那為什么最后輸出的size 是0 呢? 很好的問題,我們深入去看WeakHashMap 的源碼,我們發(fā)現了一個神奇的方法expungeStaleEntries()。在看源碼之前先解析下引用隊列的概念: 在弱引用被回收的時候會把該對象放到引用隊列中,也就意味著從引用隊列中獲取的對象都是被回收的對象,先解釋到這里,足以滿足我們下面的源碼分析了,接下來會做詳細的解析

/**
  * Expunges stale entries from the table.
  */
  private void expungeStaleEntries() {
  //這里從引用隊列里面取出一個已經被回收的對象
  for (Object x; (x = queue.poll()) != null; ) {
  synchronized (queue) {
  @SuppressWarnings("unchecked")
  Entry e = (Entry) x;
  int i = indexFor(e.hash, table.length);
  Entry prev = table[i];
  Entry p = prev;
  //下面就是通過遍歷鏈表來設置值為null 來告訴垃圾回收器回收掉
  //注意WeakHashMap 和HashMap 的數據結構都是通過數組+鏈表組成的,只有理解了這點才知道下面的代碼做了什么
  while (p != null) {
  Entry next = p.next;
  //相等的時候,就意味著這個就是要回收的對象
  if (p == e) {
  //下面就是讓回收對象不再被引用
  if (prev == e)
  table[i] = next;
  else
  prev.next = next;
  // Must not null out e.next;
  // stale entries may be in use by a HashIterator
  //這里通過設置value 為null 來告訴垃圾回收
  e.value = null; // Help GC
  size--;
  break;
  }
  prev = p;
  p = next;
  }
  }
  }
  }

從上面的代碼片段,大概的意思就是從引用隊列里面取出被回收的對象,然后和WeakHashMap 中的對象查找,找到之后就把對應的value 也設置為null,并且把對應的entry 設置為null,來告訴GC 去回收它。從源碼可以看到expungeStaleEntries() 這個方法在執(zhí)行WeakHashMap中的任何方法的時候都會被調用到的

/**
  * Expunges stale entries from the table.
  */
  private void expungeStaleEntries() {
  //這里從引用隊列里面取出一個已經被回收的對象
  for (Object x; (x = queue.poll()) != null; ) {
  synchronized (queue) {
  @SuppressWarnings("unchecked")
  Entry e = (Entry) x;
  int i = indexFor(e.hash, table.length);
  Entry prev = table[i];
  Entry p = prev;
  //下面就是通過遍歷鏈表來設置值為null 來告訴垃圾回收器回收掉
  //注意WeakHashMap 和HashMap 的數據結構都是通過數組+鏈表組成的,只有理解了這點才知道下面的代碼做了什么
  while (p != null) {
  Entry next = p.next;
  //相等的時候,就意味著這個就是要回收的對象
  if (p == e) {
  //下面就是讓回收對象不再被引用
  if (prev == e)
  table[i] = next;
  else
  prev.next = next;
  // Must not null out e.next;
  // stale entries may be in use by a HashIterator
  //這里通過設置value 為null 來告訴垃圾回收
  e.value = null; // Help GC
  size--;
  break;
  }
  prev = p;
  p = next;
  }
  }
  }
  }

到這里也就完全明白為什么value 不設置為弱引用和沒有顯性的調用remove 方法也可以回收掉了。

引用隊列

從上面的的源碼中,我們大概知道了引用隊列的使用,那為什么要使用引用隊列呢?假如沒有引用隊列,上面的例子我們就需要遍歷全部的元素一個一個的去找,如果數量少那還好,如果數量多的時候,肯定就會出現一些性能問題。有了引用隊列那就輕松可以解決上面的問題了。從WeakReference 源碼中我們可以看到有兩個構造函數,第二個是需要傳入引用隊列的

public WeakReference(T referent) {
  super(referent);
  }
  public WeakReference(T referent, ReferenceQueue q) {
  super(referent, q);
  }

總結

弱引用的出現是為了垃圾回收的

一個對象只有弱引用指向它的時候,它是可以被回收的

弱引用是在GC 發(fā)生的時候就進行回收,不管當時內存是否充足

如果你在創(chuàng)建弱引用指定一個引用隊列的話,弱引用對象被回收的時候,會把該對象放入引用隊列中

為了安全使用,每次都要判斷下是否為空來判斷該對象是否已經被回收,來避免空指針異常

以上是“Java中弱引用指的是什么意思”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注創(chuàng)新互聯行業(yè)資訊頻道!

網站名稱:Java中弱引用指的是什么意思
分享路徑:http://muchs.cn/article2/pjpoic.html

成都網站建設公司_創(chuàng)新互聯,為您提供企業(yè)建站、自適應網站、App開發(fā)面包屑導航、定制開發(fā)、小程序開發(fā)

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯

成都網站建設公司