如何克服OutOfMemoryException从API中提取大型xml文档?

时间:2012-12-04 19:21:31

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

我从API中提取1M +记录。 pull工作正常,但在尝试将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

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

4 个答案:

答案 0 :(得分:6)

听起来你的文件对你的环境来说太大了。为大文件加载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);

答案 1 :(得分:2)

当内存成为问题时,

XMLReader是要走的路。它也是最快的。

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

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));
  
}