簡體   English   中英

“使用xmlserializer時拋出了類型'System.OutOfMemoryException'的異常

[英]“Exception of type 'System.OutOfMemoryException' was thrown” while using xmlserializer

我使用以下代碼來獲取xml字符串。

public static string ToXMLString(object obj, string nodeName)
{
    XmlSerializer xmlSerializer = default(XmlSerializer);
    string xml = string.Empty;
    StreamReader r = default(StreamReader);
    try
    {
        if (obj != null)
        {
            using (MemoryStream m = new MemoryStream())
            {
                using (XmlWriter writer = XmlWriter.Create(m, new XmlWriterSettings() { OmitXmlDeclaration = true, Indent = true }))
                {
                    // Don't include XML namespace
                    XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
                    xmlnsEmpty.Add("", "");
                    if (xmlSerializer == null)
                        xmlSerializer = new XmlSerializer(obj.GetType(), new XmlRootAttribute(nodeName));
                    xmlSerializer.Serialize(writer, obj, xmlnsEmpty);

                    m.Flush();
                    m.Position = 0;

                    r = new StreamReader(m);
                    xml = r.ReadToEnd();
                    xmlSerializer = null;
                }
            }
        }

        return xml;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        throw;
    }
    finally
    {
        r.Close();
        r.Dispose();
    }
    //XmlSerializer xmlSerializer;

}

我有一個使用該方法運行的循環,一段時間后我得到一個內存不足異常,如下所示:

什么可能是例外的原因? 使用語句真正處理流嗎? 或者我可以使用其他替代品?

我希望這里的問題是裝配飽和。 XmlSerializer通過動態生成程序集來工作; 如果你使用XmlSerializer(Type)構造函數,它會緩存它並查找它; 但對於任何其他構造函數,它沒有。 並且組件不能(通常)卸載。 所以你只是得到越來越多的裝配你的記憶。 如果在循環中運行它,則需要緩存序列化程序:

using System;
using System.Collections;
using System.IO;
using System.Xml;
using System.Xml.Serialization;


public static class Program
{
    static void Main()
    {
        // the loop here is from your comment
        for (int i = 0; i < 10000000; i++) { ToXMLString("test", string.Format("test")); Console.WriteLine(i); }
    }

    // why is this Hashtable? due to the threading semantics!
    private static readonly Hashtable serializerCache = new Hashtable();

    public static string ToXMLString(object obj, string nodeName)
    {
        if (obj == null) throw new ArgumentNullException("obj");
        Type type = obj.GetType();
        var cacheKey = new { Type = type, Name = nodeName };
        XmlSerializer xmlSerializer = (XmlSerializer)serializerCache[cacheKey];
        if (xmlSerializer == null)
        {
            lock (serializerCache)
            { // double-checked
                xmlSerializer = (XmlSerializer)serializerCache[cacheKey];
                if (xmlSerializer == null)
                {
                    xmlSerializer = new XmlSerializer(type, new XmlRootAttribute(nodeName));
                    serializerCache.Add(cacheKey, xmlSerializer);
                }
            }
        }
        try
        {

            StringWriter sw = new StringWriter();
            using (XmlWriter writer = XmlWriter.Create(sw,
                new XmlWriterSettings() { OmitXmlDeclaration = true, Indent = true }))
            {
                // Don't include XML namespace
                XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
                xmlnsEmpty.Add("", "");
                xmlSerializer.Serialize(writer, obj, xmlnsEmpty);
            }
            return sw.ToString();
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex.Message);
            throw;
        }
    }
}

這里的問題可能不是這個代碼本身,而是你在這個方法之外使用生成的字符串做什么。

根據您的序列化,很可能會產生許多大字符串。 如果你繞着你的循環抓住這些字符串,你就會消耗越來越多的內存。 更糟糕的是,即使使用的絕對內存量可能不是很大,但很可能這些大字符串導致內存碎片 - GC可能無法為下一個字符串分配連續的內存塊。

在CLR中 - 大型對象(我覺得大到85KB左右)沒有分配給通常的GC代; 相反,他們進入大對象堆。 這個堆永遠不會被壓縮(除非在.Net 4中已經改變了,在這種情況下我可能不知道它)。 這意味着如果你有很多字符串被分配並被保留,那么最終會有越來越少的連續空閑空間塊足夠大以分配你的下一個字符串這是因為沒有進程可以壓縮分配的當釋放其他內存塊時,它們會一起阻塞。 如上所述,當完成這種操作時,這非常容易引起內存不足異常。

文章提供的“危險”和大對象堆的考慮一個很好的概述。

你對這個方法返回的字符串做了什么,以及生成的字符串有多大?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM