【问题标题】:How to overcome OutOfMemoryException pulling large xml documents from an API?如何克服 OutOfMemoryException 从 API 中提取大型 xml 文档?
【发布时间】:2012-12-04 19:21:31
【问题描述】:

我正在从 API 中提取 100 万多条记录。拉动工作正常,但在尝试将 ReadToEnd 转换为字符串变量时出现内存不足异常。

代码如下:

        XDocument xmlDoc = new XDocument();

        HttpWebRequest client = (HttpWebRequest)WebRequest.Create(uri);
        client.Timeout = 2100000;//35 minutes
        WebResponse apiResponse = client.GetResponse();

        Stream receivedStream = apiResponse.GetResponseStream();
        StreamReader reader = new StreamReader(receivedStream);

        string s = reader.ReadToEnd();

堆栈跟踪:

at System.Text.StringBuilder.ToString()
at System.IO.StreamReader.ReadToEnd()
at MyApplication.DataBuilder.getDataFromAPICall(String uri) in
    c:\Users\RDESLONDE\Documents\Projects\MyApplication\MyApplication\DataBuilder.cs:line 578
at MyApplication.DataBuilder.GetDataFromAPIAsXDoc(String uri) in
c:\Users\RDESLONDE\Documents\Projects\MyApplication\MyApplication\DataBuilder.cs:line 543

我可以做些什么来解决这个问题?

【问题讨论】:

  • 你应该显示相关代码。
  • 尝试循环使用reader.ReadLine() + WritetoFile 而不是reader.ReadToEnd()
  • L.B.我可以将它读入一个字符串并处理成一个 XDocument...还是我必须分解成更小的 XDocument?
  • Peacemaker,问题是 API 返回带有我必须编码的字符的 XML(例如:&),因此我必须先将其放入字符串中以对这些字符进行编码。

标签: c# .net out-of-memory


【解决方案1】:

听起来您的文件对于您的环境来说太大了。为大文件加载 DOM 可能会出现问题,尤其是在使用 win32 平台时(您尚未说明是否是这种情况)。

您可以将XmlReader的速度和内存效率与XElement/Xnode等的便利性结合起来,使用一个XStreamingElement来保存处理后的转换后的内容。这对于大文件来说更节省内存

这是一个伪代码示例:

    // use a XStreamingElement for writing
    var st = new XStreamingElement("root"); 
    using(var xr = new XmlTextReader(stream))
    {
        while (xr.Read())
        {
            // whatever you're interested in
            if (xr.NodeType == XmlNodeType.Element) 
            {
                var node = XNode.ReadFrom(xr) as XElement;
                if (node != null)
                {
                    ProcessNode(node);
                    st.Add(node);
                }
            }

        }
    }
    st.Save(outstream); // or st.WriteTo(xmlwriter);

【讨论】:

    【解决方案2】:

    XMLReader 是当内存出现问题时要走的路。它也是最快的。

    【讨论】:

      【解决方案3】:

      很遗憾,您没有显示代码,但听起来整个文件正在加载到内存中。这是你需要避免的。

      如果您可以使用流来处理文件而不将整个内容加载到内存中,则最好。

      【讨论】:

        【解决方案4】:
        class MyXmlDocument : IDisposable
            {
        
                private bool _disposed = false;
                private XmlDocument _xmldoc;
        
                public XmlDocument xmldoc
                {
                    get { return _xmldoc; }
                    
        
                }
                public MyXmlDocument()
                {
        
                    _xmldoc = new XmlDocument();
        
                }
        
                ~MyXmlDocument()
                {
                    this.Dispose();
                }
        
                // Public implementation of Dispose pattern callable by consumers.
                public void Dispose()
                {
                    Dispose(true);
                    GC.SuppressFinalize(this);
                
                }
        
                // Protected implementation of Dispose pattern.
                protected virtual void Dispose(bool disposing)
                {
                    if (_disposed)
                    {
                        return;
                    }
        
                    if (disposing)
                    {
                        // TODO: dispose managed state (managed objects).
                        this._xmldoc = null;
                        GC.Collect();
                        GC.WaitForPendingFinalizers();
                    }
        
                    // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
                    // TODO: set large fields to null.
        
                    _disposed = true;
                }
        
            }
        

        你可以使用它,然后你可以编写类似的代码

        Using(MyXmlDocument doc = new MyXmlDocument())
        {
          doc.xmldoc = xmldoc.Load(new StreamReader(file));
          
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-11-06
          • 1970-01-01
          • 1970-01-01
          • 2016-07-17
          • 2020-12-24
          • 2012-09-30
          • 2012-01-21
          • 2011-12-02
          相关资源
          最近更新 更多