.Net性能调优-ArrayPool
定义
高性能托管数组缓冲池,可重复使用,用租用空间的方式代替重新分配数组空间的行为
好处
可以在频繁创建和销毁数组的情况下提高性能,减少垃圾回收器的压力
使用
- 获取缓冲池实例:Create/Shared
var pool=ArrayPool[byte].Shared
- 调用缓冲池实例Rent()函数,租用缓冲区空间
byte[] array=pool.Rent(1024)
- 调用缓冲池实例Return(array[T])函数,归还租用的空间
pool.Return(array)
Shared
Shared返回为一个静态共享实例,实际返回了一个TlsOverPerCoreLockedStacksArrayPool
internal sealed class TlsOverPerCoreLockedStacksArrayPool<T> : ArrayPool<T>
{
private static readonly TlsOverPerCoreLockedStacksArrayPool<T> s_shared = new TlsOverPerCoreLockedStacksArrayPool<T>();
public static ArrayPool<T> Shared => s_shared;
}
特点
- 租用数组长度不可超过 2^20( 1024*1024 = 1 048 576),否则会从GC中重新开辟内存空间
- Rent租用数组实际返回的长度可能比请求的长度大,返回长度一是(16*2^n)
- Return归还缓冲区的时候,如果不设置clearArray,下一个租用者可能会看到之前的填充的值(在返回的数组长度刚好是下一个租用者请求的长度时会被看到)
- 缓冲池的内存释放不是实时释放,在缓冲区空闲时,大概10到20秒之后,会随着第2代GC一起释放,分批释放
- 并发数量持续增长时,缓冲池占用的内存空间也会持续增长,而且似乎没有上限
耗时对比
private static void TimeMonitor()
{
//随机生成3000个数组的长度值
var sizes = new int[30000];
Parallel.For(0, 10000, x => { sizes[x] = new Random().Next(1024 * 800, 1024 * 1024); });
//缓冲池方式租用数组
var gcAllocate0 = GC.GetTotalAllocatedBytes();
var watch = new Stopwatch();
Console.WriteLine("start");
watch.Start();
for (int i = 0; i < 10000; i++)
{
//CreateArrayByPool(ArrayPool<int>.Shared, 1024 * 1024,sizes[i], false);
var arr = ArrayPool<int>.Shared.Rent(sizes[i]);
for (int j = 0; j < sizes[i]; j++)
{
arr[j] = i;
}
ArrayPool<int>.Shared.Return(arr, true);
}
var time1 = watch.ElapsedMilliseconds;
var gcAllocate1 = GC.GetTotalAllocatedBytes(true);
//new 方式分配数组空间
watch.Restart();
for (int i = 0; i < 30000; i++)
{
//CreateArrayDefault(i, sizes[i], false);
var arr = new int[sizes[i]];
for (int j = 0; j < sizes[i]; j++)
{
arr[j] = i;
}
}
var time2 = watch.ElapsedMilliseconds;
var gcAllocate2 = GC.GetTotalAllocatedBytes(true);
Console.WriteLine("ArrayPool方式创建数组耗时:" + time1 + " Gc总分配量" + (gcAllocate1 - gcAllocate0));
Console.WriteLine("默认方式创建数组耗时:" + time2 + " Gc总分配量" + (gcAllocate2 - gcAllocate1 - gcAllocate0));
}
内存使用截图:左侧没有波动的横线是缓冲池执行的过程,右侧为手动创建数组的执行过程
执行结果:
ArrayPool方式创建数组耗时:17545 Gc总分配量4130800
默认方式创建数组耗时:26870 Gc总分配量37354100896
示例(前端文件通过后端Api上传OSS)
private static void PostFileByBytesPool(FormFile file)
{
HttpClient client = new HttpClient() { BaseAddress = new Uri("https://fileserver.com") };
var fileLen = (int)file.Length;
var fileArr = ArrayPool<byte>.Shared.Rent(fileLen);
using var stream = file.OpenReadStream();
stream.Read(fileArr, 0, fileLen);
MultipartFormDataContent content = new MultipartFormDataContent();
content.Add(new ByteArrayContent(fileArr, 0, fileLen), "id_" + Guid.NewGuid().ToString(), file.FileName);
client.PostAsync("/myfile/" + file.FileName, content).Wait();
ArrayPool<byte>.Shared.Return(fileArr, true);
}
Create()
ArrayPool的Create()函数会创建一个ConfigurableArrayPool对象
ConfigurableArrayPool的构造函数接收两个参数
- maxArrayLength:单次租借的数组最大长度,不可超过
1024*1024*1024
- maxArraysPerBucket:最多可以存在的未归还缓冲区数量
通过这两个参数可以解决Shared方式的两个问题:
自定义单个数组的最大长度,可以获取更大的内存空间用来存储大文件等
限定了数组的长度和最大缓冲区数量,就限定了最大的不可回收内存数量,防止高并发时缓冲池内存持续增长
示例
//创建一个自定义缓冲池实例,单个数组最大长度为1024 * 2048,最大可同时租用10个缓冲区
ArrayPool<int> CustomerArrayPool = ArrayPool<int>.Create(1024 * 2048,10);
与Shared不同的是,如果设置CustomerArrayPool=Null
那么在下一次垃圾回收时该缓冲池所占的内存会立马全部释放。
为防止不可预测的风险,应该保持CustomerArrayPool的存活。
同时为了防止内存的滥用应该限制CustomerArrayPool的数量
.Net性能调优-ArrayPool的更多相关文章
- web前端性能调优
最近2个月一直在做手机端和电视端开发,开发的过程遇到过各种坑.弄到快元旦了,终于把上线了.2个月干下来满满的的辛苦,没有那么忙了自己准备把前端的性能调优总结以下,以方便以后自己再次使用到的时候得于得心 ...
- [网站性能2]Asp.net平台下网站性能调优的实战方案
文章来源:http://www.cnblogs.com/dingjie08/archive/2009/11/10/1599929.html 前言 最近帮朋友运营的平台进行了性能调优,效果还不错, ...
- Asp.net平台下网站性能调优的实战方案(转)
转载地址:http://www.cnblogs.com/chenkai/archive/2009/11/07/1597795.html 前言 最近帮朋友运营的平台进行了性能调优,效果还不错,所以写出来 ...
- 第0/24周 SQL Server 性能调优培训引言
大家好,这是我在博客园写的第一篇博文,之所以要开这个博客,是我对MS SQL技术学习的一个兴趣记录. 作为计算机专业毕业的人,自己对技术的掌握总是觉得很肤浅,博而不专,到现在我才发现自己的兴趣所在,于 ...
- sqlserver性能调优第一步
相信不少的朋友,无论是做开发.架构的,还是DBA等,都经常听说“调优”这个词.说起“调优”,可能会让很多技术人员心头激情澎湃,也可能会让很多人感觉苦恼,不知道如何入手.当然,也有很多人对此不屑一顾,因 ...
- JavaScript:内存泄露、性能调优
1.在进行JS内存泄露检查之前,先要了解JS的内存管理: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Manageme ...
- hadoop 性能调优与运维
hadoop 性能调优与运维 . 硬件选择 . 操作系统调优与jvm调优 . hadoop运维 硬件选择 1) hadoop运行环境 2) 原则一: 主节点可靠性要好于从节点 原则二:多路多核,高频 ...
- JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用详解
摘要: JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps.jstack.jmap.jhat.jstat.hprof等小巧的工具,本博客希望 ...
- websphere性能调优之dump命令
websphere性能调优之dump命令 基于WebSphere 构建的企业应用,时常会出现性能问题,在严重的情况下还会提示出内存溢出,这是一件很让人恼怒的事情.在WebSphere Applicat ...
随机推荐
- 自学vue第二天,从入门到放弃(生命周期的理解)
生命周期的理解 beforeCreate 创建前 数据还没有监听,没有绑定到vue对象实例,同时也没有挂载对象 没有数据也没有方法 created 在创建后 数据和方法已经 data数据已经绑定好了 ...
- web浏览器知识点
网页是怎么形成的 前端的代码(英文字母)---->浏览器渲染 ------- > 客户眼中的效果 浏览器(显示代码) 游览器是网页显示,运行的平台,常用的的游览器有IE(Edge).火狐 ...
- 几个垃圾XSS
遇见帅比厂商就离谱.... 这个厂商就挖了几个反射XSS,幸亏没有浪费太多时间 嗯 有的有waf.有的没有就离谱 可以看见可以解析的,但是他的这个站,遇见关键函数就自己跳转了.然后去寻找下别的标签fu ...
- 从理发店小弟到阿里P10大牛,一位高中学渣的“登天”之路
蚂蚁金服,可能是众多程序猿眼中梦寐以求的归宿,无数拿过数不清奖状的各个高校走出的学子精英都挤破头皮,只为能在蚂蚁占有一席之地. 蚂蚁金服里不乏各种深藏不露的大佬,到了那里才会深刻明白一山还有一山高这句 ...
- Git8.3k星,十万字Android主流开源框架源码解析,必须盘
为什么读源码 很多人一定和我一样的感受:源码在工作中有用吗?用处大吗?很长一段时间内我也有这样的疑问,认为哪些有事没事扯源码的人就是在装,只是为了提高他们的逼格而已. 那为什么我还要读源码呢?一刚开始 ...
- JVM学习笔记-第三章-垃圾收集器与内存分配策略
JVM学习笔记-第三章-垃圾收集器与内存分配策略 tips:对于3.4之前的章节可见博客:https://blog.csdn.net/sanhewuyang/article/details/95380 ...
- 用Autohotkey让Kitty命令行变得更好用
下面的脚本实现Win+K键激活一个输入框,给出了kitty命令行常用的几种格式,基本可分为两种:连接保存好的模板(session)和完全手工连接,前者用-load加Session名称,后者需要在命令行 ...
- 授予mysql的其他用户数据库的使用权限
场景:不同的开发人员有不同的数据库的权限:也可适用于外包公司不同的开发权限. root用户登录数据库,命令行执行下面语句即可. grant select,delete,update,create,dr ...
- Git-09-常用命令
git常用命令 一般来说,日常使用只要记住下图6个命令,就可以了.但是熟练使用,恐怕要记住60-100个命令 下面是我整理的常用 Git 命令清单.几个专用名词的译名如下. Workspace:工作区 ...
- Spring-Boot-Bean的使用,@Repository,@Service,@Controller,@Component
前言 在Spring MVC的时候,我们使用xml来配置bean,如今的Spring boot推荐我们使用元注解的发生,那就听Spring Boot的推荐,下面我就为大家来介绍下Spring Boot ...