简单用法

//获取MemoryPool实例,实际返回了一个ArrayMemoryPool<T>
MemoryPool<char> Pool = MemoryPool<char>.Shared; //加上using
using IMemoryOwner<char> owner = Pool.Rent(1024 * 900); Memory<char> memory = owner.Memory;
for (int i = 0; i < 1024 * 900; i++)
{
memory.Span[i] = 'x';
} //从100的下标开始截取10个字符
var sliceArr = memory.Span.Slice(100, 10).ToArray();

ArrayMemoryPool<T>

通过MemoryPool<int>.Shared我们可以获取到一个MemoryPool<T>的示例,该实例的类型为ArrayMemoryPool<T>

ArrayMemoryPool<T>实际上只有一个函数可用,就是Rent(),还有一个Dispose()函数但是里面没有任何代码

Rent()限制了最大租借长度:2147483647u=(1024^3*2-1)=(2G-1bytes),并返回一个IMemoryOwner<T>对象

ArrayMemoryPoolBuffer<T>

ArrayMemoryPool<T>Rent()实际返回了一个ArrayMemoryPoolBuffer<T>,该类继承了IMemoryOwner<T>

它提供一个Memroy属性来获取一个Memory<T>对象,我们可以借助Memroy<T>来操控我们租用的数组了

ArrayMemoryPool<T>的内部实际还是调用的ArrayPool<T>.Shared 来租用数组

实现代码如下:

public Memory<T> Memory
{
get
{
T[] array = _array;
if (array == null)
{
System.ThrowHelper.ThrowObjectDisposedException_ArrayMemoryPoolBuffer();
}
return new Memory<T>(array);
}
} public ArrayMemoryPoolBuffer(int size)
{
_array = ArrayPool<T>.Shared.Rent(size);
} public void Dispose()
{
T[] array = _array;
if (array != null)
{
_array = null;
ArrayPool<T>.Shared.Return(array);
}
}

Memory<T>

Memory<T>的构造函数接收一个array<T>,存在私有变量_object中。Memory中对数组的操作最终又依赖于Span<T>

public readonly struct Memory<T> : IEquatable<Memory<T>>
{
private readonly object _object; private readonly int _index; private readonly int _length; public static Memory<T> Empty => default(Memory<T>); public int Length => _length; public bool IsEmpty => _length == 0; public unsafe Span<T> Span=>{ _object...} public T[] ToArray()
{
return Span.ToArray();
}
}

Slice(start,length)

public Memory<T> Slice(int start)
{
return new Memory<T>(_object, _index + start, _length - start);
}

Memory的Slice函数可以对数组进行截取,该函数仍然返回一个Memory<T>对象,新的对象记录了原始的_object和要切割的indexlength,所以该函数不会造成额外的内存消耗

Pin()

该函数的作用是获取数组内存的管理权,不让垃圾回收器回收,自己管理内存,但他怎么自己管理的,暂时木有研究。。。有兴趣的小伙伴可以自行研究。

但是因为我们的数组是从ArrayPool<T>租借的,由ArrayMemoryPool<T>Dispose函数回收的,所以本文对于Memory的使用方式中并不会用到该函数

所以综上所述,简单的理解就是Memory<T>主要是用来管理Span<T>

那么Span又是啥呢?为什么Memrory<T>不直接提供操作数组的方式,而是要返回一个Span<T>呢?

啊哈哈,这个就问倒我了

简单地概括其原因就是通过Span<T>来操作数组切割分片赋值等,更快,更节约内存,数据流转无复制。而Span本身过于底层,使用方面有很多的局限性。所以最终改用Memory<T>来控制Span<T>的生命周期,而只给用户提供Span的操作数组的相关函数。

至于它怎么底层了,局限性在哪些方面,想深入研究的话网上有很多相关的优秀文章值得阅读一下。对于Span的学习我现在是适可而止,后面把内存需要学习的相关知识学的差不多的时候再回来研究它吧,欠的债早晚是要还的啊...

使用场景

啊这...,对于MemoryPool,确实没有想到使用场景。因为之前的文章曾经介绍过ArrayPool。而MemoryPool的数组又是依赖ArrayPool创建的,反而相比于ArrayPool他又多了创建IMemoryOwner的消耗。这里推荐一篇文章对二者进行了对比:https://endjin.com/blog/2020/09/arraypool-vs-memorypool-minimizing-allocations-ais-dotnet。

其实我们更需要的是Memory<T>和Span<T>,在System.Memory命名空间下的MemoryExtensions为我们的Array[]提供了扩展方法AsMemory\<T\>(this T[]? array) AsSpan\<T\>(this T[]? array)等等几十种扩展,足够满足你的需要

所以如果不是非得要用MemoryPool的场景还是推荐直接使用ArrayPool吧,当然如果你有必须使用MemoryPool的场景还请在下面留言告诉我一下是什么场景,互相学习一下,嘿嘿

.Net性能调优-MemoryPool的更多相关文章

  1. [Spark性能调优] 源码补充 : Spark 2.1.X 中 Unified 和 Static MemoryManager

    本课主题 Static MemoryManager 的源码鉴赏 Unified MemoryManager 的源码鉴赏 引言 从源码的角度了解 Spark 内存管理是怎么设计的,从而知道应该配置那个参 ...

  2. web前端性能调优

    最近2个月一直在做手机端和电视端开发,开发的过程遇到过各种坑.弄到快元旦了,终于把上线了.2个月干下来满满的的辛苦,没有那么忙了自己准备把前端的性能调优总结以下,以方便以后自己再次使用到的时候得于得心 ...

  3. [网站性能2]Asp.net平台下网站性能调优的实战方案

    文章来源:http://www.cnblogs.com/dingjie08/archive/2009/11/10/1599929.html 前言    最近帮朋友运营的平台进行了性能调优,效果还不错, ...

  4. Asp.net平台下网站性能调优的实战方案(转)

    转载地址:http://www.cnblogs.com/chenkai/archive/2009/11/07/1597795.html 前言 最近帮朋友运营的平台进行了性能调优,效果还不错,所以写出来 ...

  5. 第0/24周 SQL Server 性能调优培训引言

    大家好,这是我在博客园写的第一篇博文,之所以要开这个博客,是我对MS SQL技术学习的一个兴趣记录. 作为计算机专业毕业的人,自己对技术的掌握总是觉得很肤浅,博而不专,到现在我才发现自己的兴趣所在,于 ...

  6. sqlserver性能调优第一步

    相信不少的朋友,无论是做开发.架构的,还是DBA等,都经常听说“调优”这个词.说起“调优”,可能会让很多技术人员心头激情澎湃,也可能会让很多人感觉苦恼,不知道如何入手.当然,也有很多人对此不屑一顾,因 ...

  7. JavaScript:内存泄露、性能调优

    1.在进行JS内存泄露检查之前,先要了解JS的内存管理: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Manageme ...

  8. hadoop 性能调优与运维

    hadoop 性能调优与运维 . 硬件选择 . 操作系统调优与jvm调优 . hadoop运维 硬件选择 1) hadoop运行环境 2)  原则一: 主节点可靠性要好于从节点 原则二:多路多核,高频 ...

  9. JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用详解

    摘要: JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps.jstack.jmap.jhat.jstat.hprof等小巧的工具,本博客希望 ...

随机推荐

  1. 为了彻底搞懂 hashCode,我钻了一下 JDK 的源码

    今天我们来谈谈 Java 中的 hashCode() 方法--通过源码的角度.众所周知,Java 是一门面向对象的编程语言,所有的类都会默认继承自 Object 类,而 Object 的中文意思就是& ...

  2. CTF_论剑场-web26

    is_numeric() 函数用于检测变量是否为数字或数字字符串.如果指定的变量是数字和数字字符串则返回 TRUE,否则返回 FALSE isset() - 检测变量是否设置. $str进行正则表达式 ...

  3. 搭建NFS文件共享

    1.概述: NFS(Network File System)意为网络文件系统,它最大的功能就是可以通过网络,让不同的机器不同的操作系统可以共享彼此的文件.简单的讲就是可以挂载远程主机的共享目录到本地, ...

  4. JAVA基础语法:函数(方法)、类和对象(转载)

    4.JAVA基础语法:函数(方法).类和对象 函数 在java中函数也称为方法,是一段具备某种功能的可重用代码块. 一个函数包括这几部分: 函数头 函数头包括函数访问修饰符,函数返回值类型, 函数名, ...

  5. Note about Cobertura

    Workflow of Unit Test without Cobertura compile source code; compile test code; run unit test; Workf ...

  6. .Net Core with 微服务 - 分布式事务 - TCC

    上一次我们讲解了分布式事务的 2PC.3PC .那么这次我们来理一下 TCC 事务.本次还是讲解 TCC 的原理跟 .NET 其实没有关系. TCC Try 准备阶段,尝试执行业务 Confirm 完 ...

  7. 【硬件模块】华为NBIOT 使用记录

    From: https://liudongdong1.github.io/ 1. background Low power wide area network (LPWAN) has become a ...

  8. 动态数据库PI、edna insql、infoplus简单了解

    一.动态数据库概念 动态数据库(DDL)是做为共享函数库的可执行文件.动态数据库提供了一种方法,使进程可以调用不属于其可执行代码的函数.说白了就是一个.dll可执行文件,其中有可执行代码,进程可以调用 ...

  9. Mysql 之 IFNULL(expr1,expr2) 对空不可判

    目标 当传入参数 @OrderId为空时 不做过滤 sql语句如下 SELECT o.* FROM `order` AS o LEFT JOIN receivemoneyconfirm AS re O ...

  10. 【mysql】explain性能分析

    1. explain的概念 使用EXPLAIN 关键字可以模拟优化器执行SQL 查询语句,从而知道MySQL 是如何处理你的SQL 语句的.分析你的查询语句或是表结构的性能瓶颈. 用法: Explai ...