Java の 四種引用

来源:https://www.cnblogs.com/lawsssscat/archive/2020/04/13/12689065.html
-Advertisement-
Play Games

Java 中所謂的引用,看似是指針的問題,實則體現的是JVM對記憶體的管理思想。 -- 魯迅 ...


介紹

在JAVA中提供了四種引用類型:強引用、軟引用、軟引用和虛引用。

在四種引用類型中,只有強引用FinalReference類型變數是包內可見的,其他三種引用類型均為public,可以在程式中直接使用

強引用

強引用是使用最普遍的引用。如果一個對象具有強引用,那麼垃圾回收器絕不會回收它

例如:

StringBuilder sb = new StringBuilder("test");

變數str指向StringBuffer實例所在的堆空間,通過str可以操作該對象。
如下:

  • 強引用可以直接訪問目標對象
  • 只要有引用變數存在,垃圾回收器永遠不會回收。JVM即使拋出OOM異常,也不會回收強引用所指向的對象。
  • 強引用可能導致記憶體泄漏問

軟引用

軟引用是除了強引用外,最強的引用類型。一個持有軟引用的對象,只有在記憶體不足時,gc才會回收它

可以通過java.lang.ref.SoftReference使用軟引用

SoftReference 的特點是:
一旦SoftReference保存了一個Java對象的軟引用後

  • 在垃圾線程對這個Java對象回收前,SoftReference類所提供的get()方法返回Java對象的強引用。
  • 一旦垃圾線程回收該Java對象之後,get()方法將返回null。

如下:

Object obj = new Object();
ReferenceQueue<Object> queue = new ReferenceQueue<>();
SoftReference<Object> sf = new SoftReference<Object>(obj, queue); // 只能這麼創建
obj = null;
System.out.println("引用值:" + sf.get());
System.out.println("被標記:" + sf.isEnqueued());
System.out.println("被回收:" + queue.poll());
System.gc();
System.out.println("引用值:" + sf.get() + "(gc後)"); // 有gc,不一定為null。記憶體不足時,為null
System.out.println("被標記:" + sf.isEnqueued() + "(gc後)");
System.out.println("被回收:" + queue.poll() + "(gc後)");

  • sf是對obj的一個軟引用,通過sf.get()方法可以取到 這個對象
  • 這個對象 被標記為需要回收的對象時,則返回null
    (上面例子不為null,說明對象未被gc標記為垃圾)

一個持有軟引用的對象,不會被JVM很快回收,JVM會根據當前堆的使用情況來判斷何時回收。當堆使用率臨近閾值時,才會去回收軟引用的對象。

  1. 因此,軟引用可以用於實現對記憶體敏感的高速緩存

    • 在記憶體足夠的情況下直接通過軟引用取值,無需從繁忙的真實來源查詢數據,提升速度;
    • 當記憶體不足時,自動刪除這部分緩存數據,從真正的來源查詢這些數據。
  2. 使用軟引用能防止記憶體泄露,增強程式的健壯性

    記憶體泄漏:既存在一部分記憶體一直處於空閑狀態。

  3. 軟引用可以和一個引用隊列(ReferenceQueue)聯合使用
    ReferenceQueue中保存已經失去了它所軟引用的對象的Reference對象。
    (參考“弱引用”)

    利用ReferenceQueue的poll()方法,可以檢查哪個SoftReference所軟引用的對象已經被回收,於是可以把這些失去所軟引用的對象的SoftReference對象清除掉。

弱引用

弱引用是一種比軟引用較弱的引用類型。一個被弱引用的對象,不管系統堆空間是否足夠,gc都會將對象進行回收。

在java中,可以用java.lang.ref.WeakReference實例來保存對一個Java對象的弱引用。

Object obj = new Object();
ReferenceQueue<Object> queue = new ReferenceQueue<>();
WeakReference<Object> sf = new WeakReference<Object>(obj, queue); // 只能這麼創建
obj = null;
System.out.println("引用值:" + sf.get());
System.out.println("被標記:" + sf.isEnqueued());
System.out.println("被回收:" + queue.poll());
System.gc();
System.out.println("引用值:" + sf.get() + "(gc後)"); // 只要有gc,就為null
System.out.println("被標記:" + sf.isEnqueued() + "(gc後)");
System.out.println("被回收:" + queue.poll() + "(gc後)");

弱引用的應用:WeakHashMap

Object key = new Object();
// WeakHashMap 的弱引用對象是key,而value是強引用存儲在WeakHashMap內部
WeakHashMap<Object, Object> map = new WeakHashMap<>();
map.put(key, "haha");
System.out.println("obj:" + map.get(key));
System.out.println("size:" + map.size());
System.gc();
System.out.println("obj:" + map.get(key) + "(gc後)");
System.out.println("size:" + map.size());
// 清除強引用
key = null;
// 調用gc清除弱引用
System.gc();
System.out.println("obj:" + map.get(key) + "(gc後,obj=null後)");
System.out.println("size:" + map.size());

20200413105419

最後提醒一句:WeakHashMap 不是線程安全的,要在併發場景下使用,記得使用 Collections.synchronizedMap 包一層

虛引用

虛引用是所有類型中最弱的一個。一個持有虛引用的對象和沒有引用幾乎是一樣的,隨時可能被垃圾回收器回收。當試圖通過虛引用的get()方法取得強引用時,總是會失敗。

phantom 幽靈

Object obj = new Object();
ReferenceQueue queue = new ReferenceQueue<>();
PhantomReference sf = new PhantomReference(obj, queue); // 只能這麼創建
obj = null;
System.out.println("引用值:" + sf.get());
System.out.println("被標記:" + sf.isEnqueued());
System.out.println("被回收:" + queue.poll());
System.gc();
System.out.println("引用值:" + sf.get() + "(gc後)");
System.out.println("被標記:" + sf.isEnqueued() + "(gc後)");
System.out.println("被回收:" + queue.poll() + "(gc後)");

虛引用必須和引用隊列一起使用,它的作用在於檢測對象是否已經從記憶體中刪除,跟蹤垃圾回收過程

當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在垃圾回收後,銷毀這個對象,將這個虛引用加入引用隊列。程式可以通過判斷引用隊列中是否已經加入了虛引用,來瞭解被引用的對象是否將要被垃圾回收


參考:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • react fiber 指react 16以上的版本 引入react的方式: 1、引入.js文件 2、使用腳手架工具(推薦) 推薦使用react官方提供的腳手架工具:create-react-app React開發環境準備 (npx 是 npm 的高級版本,npx 具有更強大的功能) npx cre ...
  • JavaScript 中 apply、call、bind方法的異同: 相同點 都是用來動態指定函數 this 對象的指向 第一個參數都是 this 要指向的對象,也就是要指定的上下文 都可以利用後續參數傳參 不同點 傳參形式不同:apply 方法接受的是一個參數數組,call 和 bind 方法接受 ...
  • TypeScript聯合類型 聯合類型表示取值可以為多種類型中的一種 如下所示 這一塊我們必須使用string或者number都支持的類型,那麼下麵我們可以進行調用擴展方法toString() TypeScript中對象類型 介面 介面可以描述一種抽象的行為,也可以描述對象的結構形狀,當然我們也需要 ...
  • v-bind:class=" " 綁定樣式 <div id="app"> <!-- 值是對象形式,欄位名是class樣式名,值是boolean值,true是引用該樣式,false不引用 --> <!-- 值是false,只是不引用該樣式,並不是就不顯示該元素了 --> <p v-bind:class ...
  • 前臺:支持(5+3[時尚單頁風格])八套模版,可以在後臺切換 業務模塊(首頁管理) 1. 網站信息:維護網站基本信息,比如標題、描述、關鍵詞、聯繫方式、地址等 2. 業務說明:網站首頁文字業務介紹 3. 公司理念:網站首頁展示公司的4個理念 4. 輪播圖片:網站首頁上面4個輪播圖5. 項目案例:網站 ...
  • 在前面的博客中已經介紹過如何使用Python來操作MySQL資料庫,最近需要將一批數據從csv文件中遷移到Oracle資料庫中,也打算用Python來實現,趁著這個機會,也寫一篇博客學習總結一些如何使用Python來操作Oracle資料庫。 ...
  • 原文鏈接:http://www.yiidian.com/fastjson/fastjson json javabean.html 1 簡單JSON與JavaBean的轉換 1.1 設計Student實體類 1.2 簡單JSON轉為JavaBean MainApp: 運行效果為: 1.3 JavaBe ...
  • 虛擬機 虛擬機簡介 Java 虛擬機(JVM)是運行java程式的抽象電腦,它是電腦設備的規範,可以採用不同方式進行實現,java 程式通過運行在JVM中實現跨平臺,一次編譯到處運行,不同的操作系統有不同的JDK版本,通過調用JNI方法去實現調用不同操作系統的方法 Java虛擬機不和包括java ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...