Microsoft.IO.RecyclableMemoryStream
是一个被设计为专门用于提高 Stream 操作的高性能类库,意思很明显,专用于取代 MemoryStream 而生,RecyclableMemoryStream 可以最大限度的避免 Stream 操作在 GC 上的 LOH (大对象堆)的分配和内存碎片,泄露等烦人的问题,这篇文章我们将会讨论 Microsoft.IO.RecyclableMemoryStream
及如何在 .NET Core 应用程序中提升性能。
RecyclableMemoryStream 的价值
RecyclableMemoryStream 大体上提供了如下四点价值。
使用缓冲池避免 LOH 分配。
大大的减少生成到2代堆的可能,相对减少了 GC 回收时造成的线程停滞时间。
避免了内存碎片和内存泄漏。
提供了用于跟踪和分析性能的度量值。
RecyclableMemoryStream 的原理
RecyclableMemoryStream 在2代堆上存储了一个用于流的大型缓冲区,并能够确保这个缓冲区在进程的生命周期内一直存在,这就确保了GC不会频繁的出现全量回收,同时 RecyclableMemoryStreamManager 类维护了两类缓冲池。
小型缓冲池 常用于读写操作,每一个小池子大小为 128k。
大型缓冲池 常用于当有连续缓冲的场景下使用,每一个大池子大小为 1MB。
值得注意的是,大型缓冲池的扩容又分为 线性增长
和 指数型增长
,可以看出内存可被高效的反复使用并且对调用者还是无感知的,这就是为什么 RecyclableMemoryStream 比 MemoryStream 更好更高效的原因。
当调用 GetBuffer()
方法时,小缓冲区将会转换为一个大的连续缓冲区,如下代码所示:
var buffer = recyclableMemoryStreamManager.GetStream().GetBuffer();
安装 RecyclableMemoryStream
你可以通过 Nuget 可视化界面安装 Microsoft.IO.RecyclableMemoryStream 或者通过 NuGet package manager console window 执行如下命令。
Install-Package Microsoft.IO.RecyclableMemoryStream
使用 RecyclableMemoryStream
安装好之后,接下来我们通过 RecyclableMemoryStream 将数据写入到 MemoryStream 中,值得注意的是,RecyclableMemoryStreamManager.GetStream()
方法返回的是 MemoryStream 实例。
class Program
{
private static readonly RecyclableMemoryStreamManager recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
static void Main(string[] args)
{
string data = "This is a sample text message.";
var buffer = Encoding.ASCII.GetBytes(data);
using (var memoryStream = recyclableMemoryStreamManager.GetStream())
{
memoryStream.Write(buffer, 0, buffer.Length);
}
Console.ReadKey();
}
}
上面的代码还有一点要注意,我将 RecyclableMemoryStreamManager 静态化了,意味着它只需要定义一次就ok了,还有一点你可以对 MemoryStream 进行标记,方便后续持续跟踪,如下代码所示:
using (var memoryStream = recyclableMemoryStreamManager.GetStream("High_Performance_Stream_Demo.Program.Main"))
{
memoryStream.Write(buffer, 0, buffer.Length);
}
对 MemoryStream Pool 精细化配置
如果你想对 MemoryStream Pool 做更精细化的配置,可以在 RecyclableMemoryStreamManager 实例上进行配置,如下代码所示:
int blockSize = 1024;
int largeBufferMultiple = 1024 * 1024;
int maximumBufferSize = 16 * largeBufferMultiple;
int maximumFreeLargePoolBytes = maximumBufferSize * 4;
int maximumFreeSmallPoolBytes = 250 * blockSize;
var recyclableMemoryStreamManager = new RecyclableMemoryStreamManager(blockSize, largeBufferMultiple, maximumBufferSize);
recyclableMemoryStreamManager.AggressiveBufferReturn = true;
recyclableMemoryStreamManager.GenerateCallStacks = true;
recyclableMemoryStreamManager.MaximumFreeLargePoolBytes = maximumFreeLargePoolBytes;
recyclableMemoryStreamManager.MaximumFreeSmallPoolBytes = maximumFreeSmallPoolBytes;
RecyclableMemoryStream 最佳实践
内存碎片会影响到程序的性能,而且LOH独有的链式管理也非常容易产生内存碎片,下面是使用 RecyclableMemoryStream 应该遵循的一些经验法则。
根据你的业务场景设置合适的 blockSize, largeBufferMultiple, maxBufferSize, MaximumFreeLargePoolBytes, MaximumFreeSmallPoolBytes 值。
当使用完 Stream 对象时一定要速速关闭。
永远不要调用
ToArray()
方法。尽可能避免调用
GetBuffer()
方法。
Microsoft.IO.RecyclableMemoryStream 是 MemoryStream 的池化对象,它技巧性的减少了 GC 的负载并减少了 LOH 的大对象分配,自然就提高了应用程序的性能,不仅避免了内存碎片和内存泄漏还提供了用于跟踪性能的指标。
译文链接:https://www.infoworld.com/article/3597060/how-to-use-recyclablememorystream-in-net-core.html