MemoryStream筋疲力尽

时间:2017-03-23 10:22:37

标签: c# memory-management

我正在将一些字节写入MemoryStream。我给它的大小为100 MB

  using (MemoryStream Stream = new MemoryStream())
        {             
                for ( loop 1400 time)
                {                        
                  func(i, OStream, Stream, );

                }

                lock (this)
                {                       
                 Stream.WriteTo(OStream);
                }

}

func(i, OStream, Stream)
{
  loop 19 times
      get buffer;
   Stream.Write(buffer, 0, buffer.Length);
}

缓冲区是byte[],大小从65536到116454不等。我循环1000次。 我正在写for循环,但我得到了OutOfMemoryException异常。

有没有办法扩展MemoryStream并避免异常?

1 个答案:

答案 0 :(得分:5)

考虑到数据的大小,这是最小的6000 * 65536字节,对于字节数组而言<400 MB,并且最大为6000 * 116454字节,其<500 MB。 MemoryStream会在必要时将其大小加倍,因此它首先有100 MB,然后是200 MB,然后是400 MB,可能是800 MB。

即使垃圾收集器之间无法清理,您可能会认为这最多总共2200 MB(字节数组为700,初始内存流为100,第一次扩展为200,...)。事实上,可能就是这种情况,并留下“足够”的记忆。但是,它可能无法在连续的块中使用。

您可能面临的是内存碎片问题。大量的字节数组往往超过85001字节,因此它们被分配在大对象堆上。大对象堆不会被压缩,因此会受到碎片的影响。

您可以尝试使用How to use WinDbg to track down .NET OutOfMemoryExceptions上的答案。我还发布了一个memory fragmentation example,以防你想要比较你的情况。

潜在修复

快速解决方法是编译为x64,因为那里有更多可用的内存。更清洁的方法取决于您的实际情况,并需要优化算法,例如您可以提前计算所需结果的总大小,以便MemoryStream不需要将其大小加倍。

使用单个200 kB字节数组并使用临时数据重新填充它而不是在整个地方创建新数组也可能不错。

如果您的最后任务是将数据写入文件,请使用FileStream并将其直接写入文件。

您也可以完全摆脱MemoryStream,只需将所有字节数组保存在List<byte[]>中。

可能还有很多其他解决方案......