Netty 引用計數抽象類 AbstractReferenceCountedByteBuf 詳解

核心類圖

+-----------------------------+          +----------------------------------+
|   ReferenceCountUpdater     |          |  AbstractReferenceCountedByteBuf |
| <T extends ReferenceCounted>|          | (extends AbstractByteBuf)        |
+-----------------------------+          +----------------------------------+
| - updater(): AtomicInteger  |          | - refCnt: volatile int           |
| - unsafeOffset(): long      |          | - updater: static ReferenceC..   |
+-----------------------------+          +----------------------------------+
| + retain(T, int): T         |<---------| + retain(): ByteBuf              |
| + release(T, int): boolean  |<---------| + release(): boolean             |
| + refCnt(T): int            |<---------| + refCnt(): int                  |
| + setRefCnt(T, int): void   |<---------| # setRefCnt(int): void           |
| # realRefCnt(int): int      |          | # deallocate(): void (abstract)  |
+-----------------------------+          +----------------------------------+▲                                        ▲|                                        |+----------------------------------------+通過內部匿名類或者子類實現具體操作

AbstractReferenceCountedByteBuf

在AbstractByteBuf基礎上增加了引用計數追蹤和內存生命周期管理能力

核心增強能力

1.?引用計數管理

  • 使用volatile int refCnt字段存儲引用計數(實際值需通過 ReferenceCountUpdater 解碼)。
  • 實現了retain()release()方法用于引用計數的增減
  • 委托 ReferenceCountUpdater 處理所有原子操作。

2.?內存生命周期管理

  • 當引用計數降為0時,自動觸發抽象方法 deallocate()(由子類實現具體邏輯)釋放內存
  • 提供了訪問性檢查isAccessible(),確保已釋放的ByteBuf不被誤用

具體實現能力

引用計數操作

// 增加引用計數
public ByteBuf retain()
public ByteBuf retain(int increment)// 減少引用計數,返回是否已釋放
public boolean release()
public boolean release(int decrement)// 獲取當前引用計數
public int refCnt()

生命周期控制

  • 自動內存管理: 當refCnt降為0時自動調用deallocate()
  • 訪問控制: 通過isAccessible()檢查ByteBuf是否仍然有效
  • 調試支持: 提供touch()方法用于資源泄漏檢測

線程安全保證

  • 使用AtomicIntegerFieldUpdater確保引用計數操作的原子性
  • 通過ReferenceCountUpdater統一管理引用計數的更新邏輯

?具體實現機制分析

雙重保障的線程安全設計

// 1. AtomicIntegerFieldUpdater提供CAS操作
private static final AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> AIF_UPDATER =AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCountedByteBuf.class, "refCnt");// 2. Unsafe偏移量提供底層內存訪問
private static final long REFCNT_FIELD_OFFSET =ReferenceCountUpdater.getUnsafeOffset(AbstractReferenceCountedByteBuf.class, "refCnt");

引用計數字段定義

// volatile確保可見性,通過updater訪問確保原子性
@SuppressWarnings({"unused", "FieldMayBeFinal"})
private volatile int refCnt;

生命周期管理流程

初始化階段

protected AbstractReferenceCountedByteBuf(int maxCapacity) {super(maxCapacity);updater.setInitialValue(this);  // 設置初始引用計數為1
}

引用計數操作

// 增加引用計數
public ByteBuf retain() {return updater.retain(this);    // 通過updater執行原子增操作
}// 減少引用計數并判斷是否需要釋放
public boolean release() {return handleRelease(updater.release(this));
}// 自動內存管理
private boolean handleRelease(boolean result) {if (result) {deallocate();  // 引用計數為0時自動調用}return result;
}

訪問控制檢查

boolean isAccessible() {// 非volatile讀取,提供最佳努力的訪問檢查return updater.isLiveNonVolatile(this);
}

ReferenceCountUpdater

ReferenceCountUpdater雖然是抽象類,但在AbstractReferenceCountedByteBuf中通過匿名內部類的方式實現:

private static final ReferenceCountUpdater<AbstractReferenceCountedByteBuf> updater =new ReferenceCountUpdater<AbstractReferenceCountedByteBuf>() {@Overrideprotected AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> updater() {return AIF_UPDATER;}@Overrideprotected long unsafeOffset() {return REFCNT_FIELD_OFFSET;}};

  • 定位:為引用計數對象(ReferenceCounted)提供通用原子操作邏輯。

  • 核心功能

    • 引用計數的編碼/解碼(偶數 = 活躍計數,奇數 = 已釋放)。

    • 原子性的增加(retain)和減少(release)操作。

    • 處理溢出、競爭條件及非法狀態。

  • 關鍵設計

    • 編碼機制:真實計數 = rawCnt >>> 1rawCnt 為偶數時有效)。

    • 初始值rawCnt = 2(表示真實計數為 1)。

    • 釋放標志rawCnt 為奇數(如 1)表示已釋放。

    • 基于 AtomicIntegerFieldUpdaterUnsafe 實現高效原子操作。

引用計數的編碼設計

存儲字段private volatile int refCnt

/** Implementation notes:** For the updated int field:*   Even => "real" refcount is (refCnt >>> 1)*   Odd  => "real" refcount is 0*/
  • 偶數:表示對象活躍狀態,真實引用計數 = rawCnt >>> 1(無符號右移1位)

  • 奇數:表示對象已被釋放,真實引用計數為0

  • 初始值2(二進制10),表示真實計數=1(2 >>> 1 = 1

引用計數解碼實現

private static int realRefCnt(int rawCnt) {// 快速路徑:常見值2/4直接處理,避免位運算return rawCnt != 2 && rawCnt != 4 && (rawCnt & 1) != 0 ? 0  // 奇數=>已釋放: rawCnt >>> 1; // 偶數=>真實計數
}

增加引用計數(retain

public final T retain(T instance, int increment) {int rawIncrement = checkPositive(increment, "increment") << 1; // 增量*2return retain0(instance, increment, rawIncrement);
}private T retain0(T instance, int increment, int rawIncrement) {int oldRef = updater().getAndAdd(instance, rawIncrement);// 檢查對象是否已被釋放(奇數)if (oldRef != 2 && oldRef != 4 && (oldRef & 1) != 0) {throw new IllegalReferenceCountException(0, increment);}// 溢出檢查(整數回繞)if ((oldRef <= 0 && oldRef + rawIncrement >= 0) ||(oldRef >= 0 && oldRef + rawIncrement < oldRef)) {updater().getAndAdd(instance, -rawIncrement); // 回滾操作throw new IllegalReferenceCountException(realRefCnt(oldRef), increment);}return instance;
}
  • 操作流程

    1. 將增量increment左移1位(increment << 1

    2. 原子增加字段值(getAndAdd

    3. 檢查原值:

      • 若是奇數(已釋放),拋出異常

      • 若發生整數溢出,回滾并拋出異常

減少引用計數(release

public final boolean release(T instance, int decrement) {int rawCnt = nonVolatileRawCnt(instance); // 非易失讀(性能優化)int realCnt = toLiveRealRefCnt(rawCnt, decrement); // 解碼并驗證// 關鍵分支:是否釋放到0return decrement == realCnt ? tryFinalRelease0(instance, rawCnt) || retryRelease0(instance, decrement): nonFinalRelease0(instance, decrement, rawCnt, realCnt);
}

最終釋放(歸零)

private boolean tryFinalRelease0(T instance, int expectRawCnt) {// CAS設置奇數(任何奇數均可,1最常用)return updater().compareAndSet(instance, expectRawCnt, 1); 
}private boolean retryRelease0(T instance, int decrement) {for (;;) {int rawCnt = updater().get(instance); // 易失讀(確保最新值)int realCnt = toLiveRealRefCnt(rawCnt, decrement);if (decrement == realCnt) { // 需要歸零if (tryFinalRelease0(instance, rawCnt)) return true;} else if (decrement < realCnt) { // 常規釋放int newRawCnt = rawCnt - (decrement << 1);if (updater().compareAndSet(instance, rawCnt, newRawCnt)) {return false;}} else { // 過度釋放throw new IllegalReferenceCountException(realCnt, -decrement);}Thread.yield(); // 高爭用優化}
}

常規釋放(未歸零)

private boolean nonFinalRelease0(T instance, int decrement, int rawCnt, int realCnt) {// 檢查是否滿足釋放條件if (decrement < realCnt) {int newRawCnt = rawCnt - (decrement << 1); // 計算新值// 嘗試CAS更新if (updater().compareAndSet(instance, rawCnt, newRawCnt)) {return false; // 未觸發釋放}}return retryRelease0(instance, decrement); // 進入重試
}

狀態驗證(防御性檢查)

private static int toLiveRealRefCnt(int rawCnt, int decrement) {// 快速路徑:2/4/6/8或任何偶數if (rawCnt == 2 || rawCnt == 4 || (rawCnt & 1) == 0) {return rawCnt >>> 1;}// 奇數=>已釋放對象throw new IllegalReferenceCountException(0, -decrement);
}

性能優化技巧

非易失讀優先

private int nonVolatileRawCnt(T instance) {long offset = unsafeOffset();return offset != -1 ? PlatformDependent.getInt(instance, offset) // Unsafe直接讀: updater().get(instance); // 回退到原子讀
}

PlatformDependent 最終調用?Unsafe??

  • ??無內存屏障??:讀取可能不保證其他線程的寫入可見性(除非顯式插入屏障)。
  • 類似普通變量讀取,可能觸發??指令重排序??。

??AtomicFieldUpdater??

  • 保證??volatile語義??(如AtomicIntegerFieldUpdater要求字段為volatile)。
  • 讀取前插入??LoadLoad屏障??,確保其他線程的修改可見。

快速路徑優化:在realRefCnttoLiveRealRefCnt中優先檢查常見值(2/4)

爭用處理:釋放失敗時使用Thread.yield()而非忙等

關鍵設計總結

  1. 狀態編碼

    • 奇偶性區分活躍/已釋放狀態

    • 真實計數 = 存儲值 / 2

  2. 原子性保證

    • 所有修改通過AtomicIntegerFieldUpdaterUnsafe的CAS實現

    • 歸零操作為單次CAS(設置奇數)

設計總結

1. 模板方法模式

  • ReferenceCountUpdater定義算法骨架

  • 子類實現具體的updater()unsafeOffset()方法

  • 統一了引用計數的管理邏輯

2. 性能優化

  • 雙重實現: 既支持AtomicIntegerFieldUpdater又支持Unsafe直接訪問

  • 非volatile讀取:?isLiveNonVolatile()避免不必要的內存屏障

  • 靜態工廠: 預先創建updater實例,減少運行時開銷

3. 內存安全

  • 自動釋放: 引用計數為0時自動調用deallocate()
  • 訪問控制: 通過isAccessible()防止使用已釋放的對象
  • 調試支持:?touch()方法便于資源泄漏檢測

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/86291.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/86291.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/86291.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

用Python做一個手機鏡頭

文章目錄 設置光學參數添加光學器件 設置光學參數 官方文檔&#xff1a;設計手機鏡頭 rayoptics中提供了OpticalModel類&#xff0c;可用于創建光學模型對象。OpticalModel類中的【optical_spec】成員&#xff0c;是一個OpticalSpecs對象&#xff0c;可用于指定光圈、視野、光…

16.1 Python應用容器化終極指南:Dockerfile多階段構建與安全優化實戰

Python應用容器化終極指南:Dockerfile多階段構建與安全優化實戰 #mermaid-svg-6Yor3ONhmPaQAcY6 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6Yor3ONhmPaQAcY6 .error-icon{fill:#552222;}#mermaid-svg-6Yor3ON…

基于SpringBoot + Vue打造的畫師約稿平臺實現

概述 基于SpringBoot Vue打造的畫師約稿平臺&#xff0c;該平臺設計精美、功能完善&#xff0c;無論是想要搭建類似平臺的開發者&#xff0c;還是對畫師約稿系統感興趣的人士&#xff0c;都能從中獲取有價值的信息。 主要內容 ??用戶端功能??&#xff1a; 如圖所示&…

杰理-耳機-可視化sdk-最大音量提示音-7016G

杰理-耳機-可視化sdk-最大音量提示音 1.音量最大的時候發出消息 2.通過 MSG_FROM_AUDIO 進行發送 3.創建地方接收&#xff0c;并且播放提示音 學習q群:187115320

抖音圖文帶貨權限怎么開通

在這個數字化營銷蓬勃發展的時代&#xff0c;抖音作為一個流量巨大的平臺&#xff0c;為廣大創作者和商家提供了豐富的變現途徑。其中&#xff0c;圖文帶貨權限就是一個有效的拓寬變現能力的一個渠道。 那么&#xff0c;如何才能開通抖音的圖文帶貨功能呢&#xff1f; 開通抖…

80、指標監控-Boot Admin Server

80、指標監控-Boot Admin Server Boot Admin Server是一個用于監控和管理Spring Boot應用程序的開源工具&#xff0c;以下是其相關介紹&#xff1a; #### 主要功能 - **應用狀態監控** - 顯示應用的在線狀態、啟動時間、運行時長等基本信息。 - 監控JVM指標&#xff0c;如內存…

Linux系統之Nginx反向代理與緩存

目錄 一、正向代理和反向代理 1.1 正向代理概述 1.1.1 什么是正向代理 1.1.2 正向代理的作用 1.1.3 正向代理的基本格式 1.2 反向代理概述 1.2.1 什么是反向代理 1.2.2 反向代理可實現的功能 1.2.3 反向代理的可用模塊 二、配置反向代理 2.1 反向代理配置參數 2.1.…

SpringBoot定時任務 - Timer實現方式

定時任務在實際開發中有著廣泛的用途&#xff0c;本文主要幫助你構建定時任務的知識體系&#xff0c;同時展示Timer 的schedule和scheduleAtFixedRate例子&#xff1b;后續的文章中我們將逐一介紹其它常見的與SpringBoot的集成。 知識準備 需要對定時任務的使用場景和常見的實…

系統分析師學習筆記

系統分析師學習筆記 目錄 系統分析師學習筆記前言1 數學與工程基礎&#xff08;選擇題2-4分&#xff09;1.1 圖論與應用&#xff08;考選擇題&#xff09;1.1.1 最小生成樹1.1.2 最短路徑1.1.3 網絡與最大流量&#xff08;常考&#xff09; 1.2 預測與決策&#xff08;在原有基…

《仿盒馬》app開發技術分享-- 邏輯優化第三彈(83)

技術棧 Appgallery connect 開發準備 現在我們的app功能已經趨近完善&#xff0c;bug和缺失的細節也越來越少了&#xff0c;我們繼續對app進行優化&#xff0c;首先是我們的積分頁面&#xff0c;我們只實現了全部的積分展示內容&#xff0c;對收入和支出的積分明細并沒有進行…

(七)Dockerfile文件20個命令大全詳解

目錄 1. FROM 基于基礎鏡像構建 1.1 FROM 指令開頭 1.2 ARG和FROM使用 1.3 FROM可以多個 1.4 AS name 1.5 tag和digest 2. RUN 執行任何命令 2.1 shell和exec兩種使用方式 2.2 [OPTIONS]參數 3. CMD 指定默認執行命令 3.1 使用格式shell和exec兩種使用方式 3.2 只…

攻防世界-MISC-4-2

知識點 1.字頻分析 步驟 下載附件是一段文本&#xff0c; 在線網站處理&#xff1a;quipqiup - cryptoquip and cryptogram solver flag{classical-cipher_is_not_security_hs}

Nordic nRF54L15 SoC對包含電池監測、中斷處理和電源軌控制的定制 nPM1300 示例

1&#xff1a;以下是適用于 nRF Connect SDK (NCS) 的基于 Zephyr 的示例應用程序&#xff0c;展示了&#xff1a; 讀取電池電壓和狀態處理來自 nPM1300 的中斷&#xff08;例如&#xff0c;電池或電源軌事件&#xff09;控制電源軌&#xff08;通過 GPIO 啟用/禁用&#xff0…

MySQL 單機部署

文章目錄 1、準備階段1.1、部署規劃1.2、硬件準備1.3、軟件準備1.4、環境清理 2、實施階段2.1、操作系統實施2.2、數據庫部署實施 3、完成 1、準備階段 1.1、部署規劃 本次部署用于測試環境&#xff0c;單機模式&#xff0c;不需要主備&#xff1b;MySQL數據庫版本要MySQL5.7…

小程序學習筆記:實現上拉觸底加載隨機顏色案例全解析

在前端開發中&#xff0c;上拉觸底加載數據是一個常見的交互需求。今天&#xff0c;我們就來詳細探討如何實現一個上拉觸底加載隨機顏色的案例&#xff0c;幫助大家更好地理解相關技術的應用。 案例效果展示 在這個案例里&#xff0c;我們最終要實現的效果是這樣的&#xff1…

Java+GcExcel,生成自定義工作表

引言 在當今數字化辦公和數據處理的時代&#xff0c;電子表格的應用無處不在。對于 Java 開發人員來說&#xff0c;如何高效地創建、操作和處理兼容 Microsoft Excel 的電子表格是一個常見的需求。GcExcel Java 作為葡萄城表格解決方案中的后端表格組件&#xff0c;為 Java 開…

跨平臺C++軟件開發之基本數據類型介紹

跨平臺C軟件開發過程中&#xff0c;原生數據類型的字節寬度差異是一個常見且關鍵的問題&#xff0c;不同操作系統、編譯器、硬件架構可能會為相同的數據類型分配不同的字節數&#xff0c;這可能導致代碼在移植過程中出現未定義的行為或兼容性問題。本文簡要介紹C原生數據類型字…

Java編程中的單例模式

在Java中實現單例模式有幾種方式&#xff0c;但最常見的是懶漢式和餓漢式。我們先來看一個簡單的懶漢式實現&#xff1a; public class Singleton {private static Singleton instance;private Singleton() {} // 構造方法私有化&#xff0c;防止外部實例化public static Sin…

原生微信小程序網絡請求與上傳接口封裝實戰指南

本文基于微信小程序原生 API&#xff0c;封裝 request 和 uploadFile 接口&#xff0c;最終實現統一請求管理、請求攔截、錯誤處理等能力。 &#x1f4e6; 一、為什么要封裝網絡請求&#xff1f; 微信小程序提供了 wx.request 和 wx.uploadFile 原生 API&#xff0c;但直接使用…

軟件測試基礎知識詳解

&#x1f345; 點擊文末小卡片 &#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快 1、軟件測試定義 軟件測試是指在規定的條件下對程序進行操作&#xff0c;以發現程序錯誤&#xff0c;衡量軟件質量&#xff0c;并對其是否能滿足設計要求進行…