【问题标题】:Low memory when using XmlDocument使用 XmlDocument 时内存不足
【发布时间】:2012-09-25 12:49:45
【问题描述】:

我有一个函数将生成一个数据集并从中创建一个 xml 文件。该功能运行良好。问题是多次运行报告后会出现“内存不足”错误。当我测试报告时,我发现当它到达这个 XmlDocument 命令时,内存使用量会增加很多。 我用了GC但是没用,有什么建议吗?

if (ddlDir.SelectedItem != null && ddlSec.SelectedItem != null)
{
    using (DataSet dsClosedKPICalls = GetReportData())
    {
        dsClosedKPICalls.DataSetName = "ClosedKPICalls";
        foreach (DataTable table in dsClosedKPICalls.Tables)
        {
            table.TableName = "ServiceInfo";
        }
        XmlContent = dsClosedKPICalls.GetXml();
    }

    XmlDocument XML_Data = new XmlDocument();           // contains the resultant XML data

    XML_Data.LoadXml(XmlContent);
    XmlNodeList TablesList = XML_Data.SelectNodes("ClosedKPICalls/ServiceInfo");

    for (int i = 0; i < TablesList.Count; i++)
    {
        XmlDocument innerXML = new XmlDocument();

        using (DataSet dsTaskDetails = getSplitupRecords(TablesList.Item(i).SelectSingleNode("ServiceNo").InnerText))
        {
            dsTaskDetails.DataSetName = "TaskDetails";
            foreach (DataTable tbl in dsTaskDetails.Tables)
            {
                tbl.TableName = "RequestInfo";
            }

            innerXML.LoadXml(dsTaskDetails.GetXml());

            TablesList.Item(i).AppendChild(XML_Data.ImportNode(innerXML.SelectSingleNode("TaskDetails"), true));

            innerXML = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }
}

【问题讨论】:

  • 想一想可以拆分逻辑的方法。您是否必须在一个块中处理所有表?您可以使用 XmlTextWriter 来减少内存占用吗?
  • 谢谢您的回复,能否请您再解释一下

标签: c# asp.net xmldocument


【解决方案1】:

您的 XML 文档有多大?具体来说,它们是否大于约 85K?

.Net 框架使用称为Large Object Heap (LOH) 的东西,它将用于大于~85K 的分配。如果您的 XML 文档比这大,那么 stuff(如字符串)可能会在 LOH 中分配。 LOH 的问题在于它没有被压缩,因此它容易受到内存碎片的影响,这反过来会导致OutOfMemoryExceptions 被抛出,即使进程通常应该能够分配该内存。这可能是您的问题的原因。

对于解决方案,您可以尝试

  • 通过尝试将对象的大小保持在 85K 以下来减少 LOH 的使用。根据您的应用程序,这可能很难实现,但是可以(例如)将大型 XML 文档拆分为许多较小的文档。
  • 尝试以 .Net framework v4.5 为目标,看看是否有帮助。 .Net 框架 v4.5 包含 improvements to the LOH 在这种情况下可能会有所帮助。

顺便说一句,您对GC.Collect 和GC.WaitForPendingFinalizers 的调用是个坏主意,因为这会人为地将低代对象提升到高代对象,并且通常会“弄乱垃圾收集器”。在这种情况下,这些调用几乎肯定也无济于事。作为一般规则,您应该避免手动调用垃圾回收,除非您确切地知道自己在做什么。

【讨论】:

  • 谢谢您的回复和解释,有没有其他不使用xmlDocument读取xml内容的方法?
  • @Noora 是的,XmlReader 是一个只进的 XML 阅读器,因此它允许您逐个节点地读取 XML,而无需将整个文档保存在内存中,缺点是这是很多更难使用。您可以尝试从该阅读器加载您的 XmlDocument 而不是字符串 - 它可能是放置在 LOH 中的字符串(并导致您的问题),而不是 XmlDocument 内部的任何对象。
猜你喜欢
  • 2020-02-23
  • 1970-01-01
  • 1970-01-01
  • 2017-06-05
  • 1970-01-01
  • 1970-01-01
  • 2015-05-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多