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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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;并对其是否能满足设计要求进行…