• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

.Net性能调优-ArrayPool详情

asp 搞代码 4年前 (2022-01-03) 77次浏览 已收录 0个评论
文章目录[隐藏]

ArrayPool具有高性能 托管 数组缓冲池,可重复使用,用 租用 空间的方式代替 重新分配 数组空间的行为的特点及可以在频繁创建和销毁数组的情况下 提高性能 ,减少垃圾回收器的压力的优点,下面文章内容将详细对其做介绍,需要的朋友可以参考一下

1、使用

  • 获取缓冲池实例 :Create / Shared var pool=ArrayPool[byte].Shared
  • 调用缓冲池实例 :Rent() 函数,租用缓冲区空间 byte[] array=pool.Rent(1024)
  • 调用缓冲池实例 :Return(array[T]) 函数,归还租用的空间
    来源gaodai.ma#com搞#代!码网

    pool.Return(array)

2、Shared

Shared返回为一个静态共享实例,实际返回了一个 TlsOverPerCoreLockedStacksArrayPool

 internal sealed class TlsOverPerCoreLockedStacksArrayPool : ArrayPool { private static readonly TlsOverPerCoreLockedStacksArrayPool s_shared = new TlsOverPerCoreLockedStacksArrayPool(); public static ArrayPool Shared => s_shared; } 

2.1特点

租用数组长度不可超过 2^20( 1024*1024 = 1 048 576),否则会从GC中重新开辟内存空间
Rent 租用数组实际返回的长度可能比请求的长度大,返回长度一是(16*2^n)
Return
归还缓冲区的时候,如果不设置 clearArray ,下一个租用者可能会看到之前的填充的值(在返回的数组长度刚好是下一个租用者请求的长度时会被看到)
缓冲池的内存释放不是实时释放,在缓冲区空闲时,大概10到20秒之后,会随着第2代GC一起释放,分批释放
并发数量持续增长时,缓冲池占用的内存空间也会持续增长,而且似乎没有上限

2.2耗时对比

 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.Shared, 1024 * 1024,sizes[i], false); var arr = ArrayPool.Shared.Rent(sizes[i]); for (int j = 0; j <sizes[i]; j++) { arr[j] = i; } ArrayPool.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

2.3示例(前端文件通过后端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.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.Shared.Return(fileArr, true); } 

3、Create()

ArrayPool Create()函数会创建一个 ConfigurableArrayPool 对象

ConfigurableArrayPool 构造函数接收两个参数

  • maxArrayLength :单次租借的数组最大长度,不可超过 1024*1024*1024
  • maxArraysPerBucket :最多可以存在的未归还缓冲区数量

通过这两个参数可以解决 Shared 方式的两个问题:

  • 自定义单个数组的最大长度,可以获取更大的内存空间用来存储大文件等
  • 限定了数组的长度和最大缓冲区数量,就限定了最大的不可回收内存数量,防止高并发时缓冲池内存持续增长

示例:

 //创建一个自定义缓冲池实例,单个数组最大长度为1024 * 2048,最大可同时租用10个缓冲区 ArrayPool CustomerArrayPool = ArrayPool.Create(1024 * 2048,10); 

与Shared不同的是,如果设置 CustomerArrayPool=Null 那么在下一次垃圾回收时该缓冲池所占的内存会立马全部释放。

为防止不可预测的风险,应该保持CustomerArrayPool的存活。

同时为了防止内存的滥用应该限制CustomerArrayPool的数量

到此这篇关于.Net性能调优-ArrayPool详情的文章就介绍到这了,更多相关.Net性能调优-ArrayPool内容请搜索gaodaima搞代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持gaodaima搞代码网

以上就是.Net性能调优-ArrayPool详情的详细内容,更多请关注gaodaima搞代码网其它相关文章!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:.Net性能调优-ArrayPool详情

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址