"类型System.OutOfMemoryException引发的异常"同时采用的XmlSerializer异常、类型、QUOT、System

2023-09-06 05:08:27 作者:放下所有痛

我使用下面的code以获得一个XML字符串。

I am using the following code to get an xml string.

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;

}

我有运行使用该方法的循环,并在一段时间后我得到一个内存不够的异常如下:

I have a loop that runs using the method and after some time i get an out of memory exception as below:

可能是什么异常的原因是什么?正在使用的语句真的处理流?或者,我可以用什么其他的选择吗?

What might the cause of the exception? Is using statement really disposing streams? Or what other alternative can i use?

推荐答案

我希望这里的问题是组装饱和。 的XmlSerializer 的工作原理是产生在飞行的组件;如果您使用的XmlSerializer(类型)的构造函数,它缓存它,并期待它;但对于其他构造事实并非如此。和组件不能(通常)被卸载。所以,你只得到越来越多的集吃你的记忆。您将需要缓存,如果你是在一个循环中运行这个串行:

I would expect the issue here is assembly saturation. XmlSerializer works by generating an assembly on the fly; if you use the XmlSerializer(Type) constructor, it caches it and looks it up; but for any other constructor it doesn't. And assemblies can't (usually) by unloaded. So you just get more and more and more assemblies eating your memory. You will need to cache the serializer if you are running this in a loop:

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;
        }
    }
}
 
精彩推荐