【问题标题】:very large string in memory内存中非常大的字符串
【发布时间】:2011-02-20 06:10:06
【问题描述】:

我正在编写一个程序,用于将 100 多个 MB 字符串数据(接近演出)格式化为 xml == 我需要将其作为对 HTTP (GET) 请求的响应返回。

我正在使用 StringWriter/XmlWriter 在循环中构建记录的 XML 并返回

using (StringWriter writer = new StringWriter())
using (writer = XmlWriter.Create(writer, settings)) //where settings are the xml props

writer.ToString() 

在测试过程中,我看到了一些 -- 内存不足异常 -- 并且对如何找到解决方案一无所知?你们对响应的内存优化传递有什么建议吗?

是否有一种内存有效的数据编码方式?或者可能对数据进行分块—— 如果不将整个东西构建到一个巨大的字符串对象中,我就是想不出如何返回它

谢谢

-- 一些澄清—— 如 josh 所述,这是一个通过千兆以太网链接的 asp .net webservices 应用程序。我对它不是很熟悉,所以还是有点学习曲线。

我正在使用 XMLWriter 创建 XML 并使用 String 从中创建一个字符串

一些统计数据—— 响应 xml 大小 = 大约 385 兆(我的数据大小会很快增长到远不止这些)

由内存分析器计算的字符串对象大小 = 峰值为 605MB

感谢所有回复的人......

【问题讨论】:

  • 1GB 的 xml 作为 HTTP 响应?真的吗?
  • 我很想说“扔一些硬件”(开玩笑)。每个客户端 500 MB(或 350 MB 或 1GB)不可扩展。也许您可以进一步了解您正在生成的 XML。这个msdn.microsoft.com/en-us/library/aa528818.aspx 可能会有所帮助。
  • 多么有见地——我相信这是管理层选择的解决方案:)

标签: c# string memory memory-management memory-leaks


【解决方案1】:

使用 XmlTextWriter 包裹 Reponse.OutputStream 将 XML 发送到客户端并定期刷新响应。这样,您在任何时候都不必拥有超过几 MB 的内存(至少对于发送到客户端而言)。

【讨论】:

  • 听起来他正在使用字符串操作来组装 XML。
  • @SLaks,听起来他可以做任何事情,因为他真的没有说。
  • +1。或者甚至将XmlTextWriter 环绕在GZipStream 周围环绕Response.OutputStream。
【解决方案2】:

您不能将响应流式传输到客户端吗? XmlWriter 不需要将其底层流缓冲在内存中。如果是 ASP.NET,则可以使用 Response.OutputStream,如果是 WCF,则可以使用 response streaming。

【讨论】:

  • Josh,这是一个 Web 服务项目——客户端通过 GET 向 Web 方法发出请求——对于微软解决方案来说是新手,我不确定它是否可能以及如何实现
  • 这对于 ASMX Web 服务来说可能是不可能的,如果你正在使用它,我强烈建议您在重新设计太困难之前立即迁移到 WCF。您已经遇到了 ASMX 的限制之一,还有很多其他限制不仅限于性能。但是使用 WCF,您可以返回一个 Stream 对象并将数据分块给调用者。都是内置的。
  • 谢谢乔希!所有人都提出了很好的意见,但会将其标记为适当的答案。
【解决方案3】:

HTTP 获取 1 个演出?好多啊!也许你应该重新考虑。 至少对输出进行 gzip 压缩会有所帮助。

【讨论】:

  • 如果他仍然以这种方式构建 XML,Gzipping 将无济于事。问题不在于数据的传输,而在于它在发送之前被缓冲在内存中。 HTTP GET 没有实际限制。特别是考虑到您可以恢复中断的下载,我们不知道他通过什么类型的网络发送它。可能是千兆以太网!
【解决方案4】:

您不应该使用字符串操作来创建 XML。

相反,您应该使用 XmlTextWriter、XmlDocument 或(在 .Net 3.5 中)XElement 类在内存中构建 XML 树,然后使用 XmlTextWriter 将其直接写入 Response.OutputStream。

直接写入包装Response.OutputStream 的XmlTextWriter 将是最有效的(您永远不会一次在内存中拥有整个元素树),但会稍微复杂一些。

通过这种方式,您将永远不会有一个包含整个对象的字符串(或数组),因此应该避免 OutOfMemoryExceptions。

【讨论】:

  • XmlDocument 和 XElement 将表现出与字符串操作相同(实际上更糟)的内存问题!构建大型 XML 结构只能使用 XmlWriter API 完成。
  • 如果你没有足够的连续内存,你仍然可以得到内存不足的异常。更改写入流的方法似乎更合理。
  • @Josh:不会。只有String 和Array 会分配大块连续内存。
  • 确实如此,但 XmlDocument/XElement 消耗的总内存将比其字符串生成器对应物大得多。无论哪种方式,在内存中保存这么多数据只是在请求 DoS 攻击。
  • 不开玩笑。我讨厌那个 API。但是在处理这种规模的数据时,开发人员只需要吸收它并以正确的方式进行操作,否则 sh*t 有一天会开始崩溃,通常是在您正在部署新的计费系统时逾期 6 个月。
【解决方案5】:

遇到了类似的问题,希望对大家有所帮助。我的初始代码是:

var serializer = new XmlSerializer(type);
string xmlString;

using (var writer = new StringWriter())
{
    serializer.Serialize(writer, objectData, sn); // OutOfMemoryException here
    xmlString = writer.ToString();
}

我最终用 MemoryStream 替换了 StringWriter,这解决了我的问题

using (var mem = new MemoryStream())
{
    serializer.Serialize(mem, objectData, sn);
    xmlString = Encoding.UTF8.GetString(mem.ToArray());
}

【讨论】:

    【解决方案6】:

    您必须在各自的 GET 上返回每条记录(或一小组记录)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-23
      • 1970-01-01
      • 1970-01-01
      • 2019-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多