ArrayPool.Shared解说

news/2025/9/29 0:16:19/文章来源:https://www.cnblogs.com/kewei/p/19117863

ArrayPool简介

.NET 中频繁创建和销毁数组的情况下会导致垃圾回收器出现严重的内存压力,ArrayPool<T> 通过池化手段有效地降低了数组的分配和垃圾回收器的回收压力,同时 ArrayPool<T> 也是 MemoryPool<T> 和 PipeWriter、PipeReader 的底板。

ArrayPool<T>.SharedArrayPool<T> 的一种实现,它设计成静态共享以供全体共同使用。在实际应用中, Shared 实例几乎承载了全部的 ArrayPool<T> 调用。

Shared实例的Rent

static void RentAndReturn(int size)
{var pool = ArrayPool<byte>.Shared;var array = pool.Rent(size);// 在这里使用 arraypool.Return(array); 
}

其中输入的 size 和 Rent 得到 array.Length的关系如下:

var index = SelectBucketIndex(size);
var arrayLenth = GetMaxSizeForBucket(index);static int SelectBucketIndex(int size)
{return BitOperations. Log2((uint)((size - 1) | 0xF)) - 3;             
}static int GetMaxSizeForBucket(int bucketIndex)
{return 16 << bucketIndex;
}

调用 SelectBucketIndex(int.MaxValue) 会得到27,实际上 Shared 实现只维护最大索引值为 26 的总共 27 个 Bucket,所以当你 Rent 出大于 1GB 的数组时永远触发分配且不会 Return 到 Bucket 里。

Shared实例的Return

如果我们书写如下代码,会发生什么情况?

var pool = ArrayPool<byte>.Shared;var array1 = new byte[16];
pool.Return(array1);var array2 = new byte[16];
pool.Return(array2);

array1 和 array2 都不是 Rent 出来的,Return 操作 pool 会接受吗?
答案是都接受,只要 array.Length 符合要求都会接受,而且也不会考虑多次 Return 同一个引用 array 的特殊情况。所以千万不要对同一个 Rent 到的 array 实例进行多次 return 操作。

Shared实例的Thread-Local-Storage

如果我们书写如下代码,会触发 Shared 的 Buckets 读写访问吗?

var pool = ArrayPool<byte>.Shared;
for(var i =0; i <100; i++)
{var array = pool.Rent(1024 * 1024);pool.Return(array);
}

答案是不会触发 Buckets 读写访问,执行之后 27 个 Bucket 还是未初始化的 null 值,因为Shared使用Thread-Local-Storage做了第一层无锁缓存。

原始代码

[ThreadStatic]
private static SharedArrayPoolThreadLocalArray[]? t_tlsBuckets;

方便理解的简化代码

// 创建一个 Array 类型的数组,数组共27个元素
// 每个元素的索引值,对应 Bucket 的索引
[ThreadStatic]
private static Array? [] t_tlsBuckets = new Array[27];

当执行

var array = ArrayPool<byte>.Shared.Rent(16);

实际的逻辑是

var index = SelectBucketIndex(16); // index = 0;
var array = t_tlsBuckets[index];  
if(array != null)
{t_tlsBuckets[index] = null;  // 当然这里不会对t_tlsBuckets进行2次索引访问,使用 ref 来解决return array;
}

Return 的时候也是一样的缓存访问逻辑,当 t_tlsBuckets 索引对应的元素为 null 时缓存成功。

Shared实例的Buckets

当 t_tlsBuckets[index] 缓存不命中时,会触发 Bucket = Buckets[index] 的创建和访问。注意这里一个 Bucket 不是 Array的集合,而是Array的集合的集合,我们叫他Partitions。为了方便理解,下面给出示意代码:

// bucket 是 Partition 的集合,Partition 是 Array 的集合
// bucket 的元素数量是 Environment.ProcessorCount
List<Partition> bucket = Buckets[index]; 
Debug.Assert(bucket.Count == Environment.ProcessorCount);

当进行 Rent 操作时,尝试从 bucket 里弹出一个 Array,其示意过程如下(注意真实的实现为高性能代码可理解性更难):

// bucket 是 Partition 的集合,Partition 是 Array 的集合
// bucket 的元素数量是 Environment.ProcessorCount
List<Partition> bucket = Buckets[index]; 
// 每个 cpu 核心操作固定的一个 Partition,目的是去锁化
int cpuIndex = Thread.GetCurrentProcessorId() % Environment.ProcessorCount;
Partition cpuPartition = bucket[cpuIndex];// Partition 的元素数量固定是 32
Debug.Assert(cpuPartition.Count == 32);// 尝试从当前 cpu 核心对应的 Partition 进行TryPop()
// TryPop() 的实现有排他锁,但这里只要没有别的线程来访问此 Partition,就不会产生互斥
// 如果在同一线程下租赁过32次且不归还,TryPop()会失败
Array array = null;
if ((array = cpuPartition.TryPop()) != null)
{return array;
})// 以上失败后则尝试从其它的 Partition TryPop(),此时排他锁可能就生效了
for(var index = 0; index < bucket.Count; index++)
{if(index!= cpuIndex){Partition otherPartition = bucket[index];if ((array = otherPartition.TryPop()) != null){return array;})}
}return null;

在进行 Return 操作是,大的流程和 Rent 一样,不同是 TryPop() 变成了TryPush()。
总结一下,在指定 size 之后,Shared 实例最多能 Rent(size) 出 Environment.ProcessorCount * 32 个可复用的数组,伴随着 Return 的及时性越低,Rent 时排它锁触发的几率就越高。

总结

以为是本人对 ArrayPool.Shared 实现的分析和理解,并变换成一种相对容易理解的伪代码,如有不对之处请指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/921287.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站添加视频代码seo网站分析

linux中fork&#xff08;&#xff09;函数详解 一、fork入门知识 一个进程&#xff0c;包括代码、数据和分配给进程的资源。fork&#xff08;&#xff09;函数通过系统调用创建一个与原来进程几乎完全相同的进程&#xff0c;也就是两个进程可以做完全相同的事&#xff0c;但如果…

工程建设期刊网站网站怎么做vga头

前言 在现代应用程序中&#xff0c;实时通信已经成为了一种必需的特性。而Websocket是一种在客户端和服务器之间建立持久连接的协议&#xff0c;可以实现实时的双向通信。Golang作为一门高效且简洁的语言&#xff0c;也提供了一些优秀的Websocket框架&#xff0c;方便开发者构…

新手有关网站建设需要看哪些书公司网站建设管理

问题描述&#xff1a; 开始一直用的 XFTP 后来&#xff0c;它变成收费软件了&#xff0c;所以使用filezilla 代替 XFTP 之前用的还好好的&#xff0c;今天突然就报错了&#xff1a;按要求输入相关字段&#xff0c;连接 连接失败&#xff01;&#xff01;&#xff01;o(╥﹏╥…

网站自助搭建平台鞍山微信小程序开发公司

1&#xff0c;服务配置service文件 Service 服务的实际作用是开启后自动启动服务&#xff0c;运行一些不须要登录的程序&#xff0c;任务。 实例1、上电自动连接WIFI热点 1.1 新建.service文件 /etc/systemd/system/wificonnect.service [Unit] DescriptionService [wifico…

PS与可画基础介绍

学生会平设部首次培训内容涵盖PS和可画的基础操作。PS部分介绍了常用快捷键、工具使用(如椭圆选框、套索、魔棒)、图层管理技巧、抠图方法(颜色区间法和智能抠图)以及渐变色设置。可画部分强调其模板化设计的便捷性…

OpenMP并行化编程指南

OpenMP -- C/C++ -- 密码工程OpenMP并行化编程指南 核心思想:基于线程的共享内存并行 OpenMP 的核心思想是 “ Fork-Join ” 并行模型。程序开始时是一个单线程(主线程),在遇到需要并行计算的区域时,主线程派生出…

OneNote 安装 OneNote Gem 的第三方插件

https://cn.onenotegem.com/a/documents/gem-for-onenote/2019/1113/390.html https://cn.onenotegem.com/a/addins/gem-for-onenote.html双击 exe 开始安装:

南宁网站快速优php怎么建立网站

EFK日志系统搭建 EFK日志系统介绍功能需求搭建elasticsearch集群规划前提部署核对证书及权限 EFK日志系统介绍 Elasticsearch 是一个实时的、分布式的可扩展的搜索引擎&#xff0c;允许进行全文、结构化搜索&#xff0c;它通常用于索引和搜索大量日志数据&#xff0c;也可用于…

如何建设国外的网站昆明网红打卡景点

紫外光电探测器被广泛应用于导弹预警、火灾探测、非可见光通信、环境监测等民事和军事领域&#xff0c;这些应用场景的实现需要器件具有高信噪比和高灵敏度。因此&#xff0c;光电探测器需要具备响应度高、响应速度快和暗电流低的特性。近期&#xff0c;天津赛米卡尔科技有限公…

2025.9.28总结

应软件案例分析课程要求做一个c/s架构的软件 下载编译器visual studio 社区版,下载c#环境,在ai帮助下完成了示例服务器,客户端的撰写,并在本地运行,接下来需要完成 1.连接mysql数据库 2.能以我的电脑为服务器端,…

淘宝优惠券返利网站怎么做c 能用来做网站

注意在使用金橙子根据对象名称删除对象时要注意,每删除一个对象,所有对象的索引都将改变。 如果你是用for去遍历,再根据索引获取打标对象名称的话就会出现漏的掉的问题。 改进方法 1,将要删除的对象找到后,统一存放在一个集合中。再根据这个要删除的对象集合再一个个去遍…

7个免费的PPT模板下载网站,新手也能做出高级感PPT!

做 PPT 找不到好模板真的能急到挠头!要么风格老土撞款率高,要么下载要收费、商用有版权坑,花大半天搜的模板还得大改格式。不管是职场汇报、学术答辩还是创意展示,好模板都能让演示效果翻倍。今天就把亲测好用的 7…

[ERR] 1118 - Row size too large ( 8126)

1、错误: 之前用的mysql5.6,备份数据库后,在mysql8中进行还原数据库,出现错误: [ERR] 1118 - Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FOR…

数据类型-字典

字典(可变类型):info = {"k1":1,"k2":"222","k3":"guohan"} 可变类型不可以做字典的键(列表,字典,集合) 公共功能:1.索引:info["k1"] 通…

牛客刷题-Day7

动态规划1:线性dp、背包问题,区间 https://ac.nowcoder.com/acm/contest/24213?from=acdiscuss牛客刷题-Day7 今日刷题:\(1031-1035\) 1032 迁徙过程中的河流 题目描述 牛市的幸存的先民在流星雨之后就忍痛离开了这…

做网站类的书本信息网络建构是什么意思

ELK/EFK日志系统 如果今天谈论到要部署一套日志系统&#xff0c;相信用户首先会想到的就是经典的ELK架构&#xff0c;或者现在被称为Elastic Stack。 Elastic Stack架构为Elasticsearch Logstash Kibana Beats的组合&#xff0c;其中&#xff0c;Beats负责日志的采集&…

第2周

1 nginx配置结构和流量逻辑过程 1.1 nginx配置结构全局配置段:控制软件运行 events配置段:配置Nginx的事件驱动模型和连接处理机制(接收连接用户) http配置段:配置http服务的全局参数(处理连接)Server配置段:定义虚…

步进电机T型加减速

步进电机T型加减速【嵌入式必读】彻底理解步进电机梯形加减速运动算法原理_步进电机梯形加减速算法-CSDN博客 【嵌入式必读】【一文彻底理解】步进电机驱动算法——梯形加减速运动算法代码实现_步进电机加减速程序编写…

知名的建站公司找人做短视频网站

标准是可以分类的。比如根据层次、专业、对象、目的、功能等维度进行分类。 以层次进行分类&#xff1a; 可以分为国际标准、区域标准、国家标准、团体标准、企业标准、行业标准 以专业进行分类&#xff1a; 可以分为农业、医药、卫生、劳动保护、矿业、化工、机械等等。 以对象…

做网站为什么要投资钱诸城 建设外贸网站

图神经网络实战——图论 0. 前言1. 图属性1.1 有向图和无向图1.2 加权图与非加权图1.3 连通图非连通图1.4 其它图类型 2. 图概念2.1 基本对象2.2 图的度量指标2.2 邻接矩阵表示法 3. 图算法3.1 广度优先搜索3.2 深度优先搜索 小结系列链接 0. 前言 图论 (Graph theory) 是数学…