浅析池化对象 RecyclableMemoryStream 在 .netcore 中的使用

开发 前端
这篇文章我们将会讨论 Microsoft.IO.RecyclableMemoryStream 及如何在 .NET Core 应用程序中提升性能。

[[385657]]

 本文转载自微信公众号「码农读书」,作者码农读书。转载本文请联系码农读书公众号。

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() 方法时,小缓冲区将会转换为一个大的连续缓冲区,如下代码所示:

  1. var buffer = recyclableMemoryStreamManager.GetStream().GetBuffer(); 

安装 RecyclableMemoryStream

你可以通过 Nuget 可视化界面安装 Microsoft.IO.RecyclableMemoryStream 或者通过 NuGet package manager console window 执行如下命令。

  1. Install-Package Microsoft.IO.RecyclableMemoryStream 

使用 RecyclableMemoryStream

安装好之后,接下来我们通过 RecyclableMemoryStream 将数据写入到 MemoryStream 中,值得注意的是,RecyclableMemoryStreamManager.GetStream() 方法返回的是 MemoryStream 实例。

  1. class Program 
  2.  { 
  3.      private static readonly RecyclableMemoryStreamManager recyclableMemoryStreamManager = new RecyclableMemoryStreamManager(); 
  4.  
  5.      static void Main(string[] args) 
  6.      { 
  7.          string data = "This is a sample text message."
  8.  
  9.          var buffer = Encoding.ASCII.GetBytes(data); 
  10.           
  11.          using (var memoryStream = recyclableMemoryStreamManager.GetStream()) 
  12.          { 
  13.              memoryStream.Write(buffer, 0, buffer.Length); 
  14.          } 
  15.           
  16.          Console.ReadKey(); 
  17.      } 
  18.  } 

上面的代码还有一点要注意,我将 RecyclableMemoryStreamManager 静态化了,意味着它只需要定义一次就ok了,还有一点你可以对 MemoryStream 进行标记,方便后续持续跟踪,如下代码所示:

  1. using (var memoryStream = recyclableMemoryStreamManager.GetStream("High_Performance_Stream_Demo.Program.Main")) 
  2.             { 
  3.                 memoryStream.Write(buffer, 0, buffer.Length); 
  4.             } 

对 MemoryStream Pool 精细化配置

如果你想对 MemoryStream Pool 做更精细化的配置,可以在 RecyclableMemoryStreamManager 实例上进行配置,如下代码所示:

  1. int blockSize = 1024; 
  2. int largeBufferMultiple = 1024 * 1024; 
  3. int maximumBufferSize = 16 * largeBufferMultiple; 
  4. int maximumFreeLargePoolBytes = maximumBufferSize * 4; 
  5. int maximumFreeSmallPoolBytes = 250 * blockSize; 
  6. var recyclableMemoryStreamManager = new RecyclableMemoryStreamManager(blockSize, largeBufferMultiple, maximumBufferSize); 
  7. recyclableMemoryStreamManager.AggressiveBufferReturn = true
  8. recyclableMemoryStreamManager.GenerateCallStacks = true
  9. recyclableMemoryStreamManager.MaximumFreeLargePoolBytes = maximumFreeLargePoolBytes; 
  10. 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

责任编辑:武晓燕 来源: 码农读书
相关推荐

2009-07-01 09:17:36

对象比较Java

2009-06-16 15:20:48

ApplicationJSP程序

2017-05-24 09:43:42

2011-08-29 17:27:47

HTML 5交互移动应用

2009-09-29 16:11:45

Hibernate实现

2010-03-15 17:17:29

Java线程池

2009-09-28 13:23:54

HTTP编程

2009-09-11 11:33:58

C# WinForm控Attribute

2009-08-25 15:15:08

C#对象序列化应用

2011-03-11 09:20:35

jQueryjavascript

2021-07-15 08:58:16

Spring对象引用

2023-10-10 10:02:32

2013-11-07 09:42:42

对象对象池加速

2021-07-27 22:56:00

JavaScript编程开发

2009-07-29 15:55:48

ASP.NET Req

2012-06-13 09:29:28

2009-09-09 14:45:41

XML序列化和反序列化

2011-06-19 08:59:59

锚文本

2021-08-29 22:05:04

对象自动回收

2024-06-13 00:54:19

点赞
收藏

51CTO技术栈公众号