【问题标题】:OutOfMemory Exception while converting MemoryStream to Array将 MemoryStream 转换为 Array 时出现 OutOfMemory 异常
【发布时间】:2016-12-08 09:57:26
【问题描述】:

我使用下面的代码在HttpResponseMessage中返回一个字节数组:

using (WebResponse response = (HttpWebResponse)request.GetResponse())
{
   byte[] bytes = ReadFully(response.GetResponseStream());
   ......
}
public static byte[] ReadFully(Stream input)
{
  byte[] buffer = new byte[16*1024];
  using (MemoryStream ms = new MemoryStream())
  {
    int read;
    while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        ms.Write(buffer, 0, read);
    }
    return ms.ToArray(); // This line throws OutOfMemory exception
  }
}

在最后一个 return ms.ToArray() 语句中引发了 OutOfMemory 异常。

我需要将生成的byte[] 设置为HttpResponseMessage.Content

【问题讨论】:

  • 流有多大?为什么不直接写入响应流?
  • 大约 250MB...
  • 你在使用 ASP.NET MVC 吗? File() 辅助函数接受流参数,其他函数也是如此。 250MB 是 lot 用于本地缓存,仅用于复制到另一个流
  • 只需尝试使用响应流实例化 StreamReader,然后使用 StreamReader.ReadToEnd()。这将为您提供结果字符串
  • @Radinator 为什么你认为分配 250MB 的字符串会比分配任何其他 250MB 对象的内存问题更少?

标签: c# arrays exception out-of-memory memorystream


【解决方案1】:

您应该直接返回流,而不是先将其读入内存。

public HttpResponseMessage CreateMessage(Stream input)
{
    HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
    result.Content = new StreamContent(input);
    return result;
}

不要忘记设置适当的标题等。


编辑

...我需要将 HttpResponseMessage 中的字节数组写入文件

根据您上次的评论,您更改了问题并想换一种方式。这是一个从 Web 响应写入文件的示例。

public void writetoFile(HttpWebResponse response)
{
    var inStream = response.GetResponseStream();
    using (var file = System.IO.File.OpenWrite("your file path here"))
    {
        inStream.CopyTo(file);
    }
}

【讨论】:

    【解决方案2】:

    Igor 发布了解决方案,以及处理流内容的正确方法。使用 File(stream,contentype) 之类的 MVC 辅助函数之一或 StreamContent 之类的类将流内容直接发送到客户端,例如:

    return File(myStream,myExcelContentTypeString);
    

    return File(myStream,myExcelContentTypeString,"ReallyBigFile.xlsx");
    

    错误的原因,是因为内存太碎片化而无法分配新对象,可能会发生OOM。 MemoryStream 将数据存储在缓冲区中。当它超过缓冲区限制时,它会分配一个容量翻倍的新数据并复制旧数据。像这样复制 250MB 的数据会导致 大量 重新分配,从而导致大量内存碎片。

    这可以通过在流的构造函数中指定所需的容量来避免。这将立即分配足够大的缓冲区。

    最好避免缓存这些内容,直接将其发送到浏览器。

    【讨论】:

      猜你喜欢
      • 2020-11-27
      • 1970-01-01
      • 1970-01-01
      • 2017-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多