在StringWriter.ToString()中出现OutOfMemoryException

本文关键字:OutOfMemoryException StringWriter ToString | 更新日期: 2023-09-27 18:03:02

在StringWriter上调用ToString时,我得到了一个OutOfMemoryException:

StringWriter stringWriter = new System.IO.StringWriter();
XmlSerializer serializer = new XmlSerializer(typeof(T));
serializer.Serialize(stringWriter, data);
string xmlString = stringWriter.ToString(); // <-- Exception occurs here

如何解决这个问题?

在StringWriter.ToString()中出现OutOfMemoryException

试试下面的代码。它使用文件作为临时缓冲区。

List<Dummy> lst = new List<Dummy>();
        for (var i = 0; i < 100000; i++)
        {
            lst.Add(new Dummy()
                    {
                        X =  i,
                        Y =  i * 2
                    });
        }
        XmlSerializer serializer = new XmlSerializer(typeof(List<Dummy>));
        // estimate your memory consumption ... it would be around 4 bytes reference + 4 bytes object type pointer + 8 bytes those ints + let's say another 4 bytes other hidden CLR metadatas. a total of 20 bytes per instance + 4 bytes reference to our object (in the list array) => around 24 bytes per instance. Round up to a let's say 50 bytes per instance. Multiply it by 100.000 = 5.000.000
        MemoryStream memStream = new MemoryStream(5000000);
        serializer.Serialize(memStream, lst);
        memStream.Position = 0;
        string tempDatafileName = null;
        var dataWasWritten = false;
        try
        {
            var fileName = Guid.NewGuid().ToString() + ".tempd";
            var specialFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
            using (var fs = new FileStream(tempDatafileName, FileMode.Create, FileAccess.ReadWrite))
                memStream.WriteTo(fs);
            dataWasWritten = true;
            memStream.Dispose();
            memStream = null;
            lst.Clear();
            lst = null;
            // force a full second generational GC
            GC.Collect(2);
            // reading the content in string
            string myXml = File.ReadAllText(tempDatafileName);
        }
        finally
        {
            if (dataWasWritten && string.IsNullOrWhiteSpace(tempDatafileName) == false)
            {
                if (File.Exists(tempDatafileName))
                {
                    try
                    {
                        File.Delete(tempDatafileName);
                    }
                    catch
                    {
                    }
                }
            }
        }

这应该能奏效:

using (StreamWriter sw = File.AppendText(path))
{
    using (StreamReader sr = new StreamReader(ms))
    {
        while (sr.Peek() >= 0)
        {
            string l = sr.ReadLine();
            sw.WriteLine(l);
        }
    }
}

我确信stringWriter已经非常大了,假设大小超过1gb,并且您的计算机的总内存为2gb。当您调用ToString()时,内存将增加一倍,因为将创建一个新的字符串并在大小为1GB的堆中分配,以便能够复制stringWriter的内容。尽量避免不必要的ToString(),并尝试直接使用stringWriter完成需要做的事情。避免使用ToString(),通常可以减少50%的内存占用。

但是,如果你真的需要你的数据作为字符串,你没有足够的内存,尝试先保存内容在一个文件中,处置StringWriter和文件内容加载到一个字符串使用StreamReader。ReadToEnd () API.

另一种方法是尝试将序列化的数据分割成块,并尝试在块中解析它。例如,让我们考虑一个具有如下结构的XML:

<Root>
    <Item>some data 1</Item>
    <Item>some data 2</Item>
    <Item>some data 3</Item>
    ....
    <Item>some data n</Item>
</Root>

你可以序列化你的对象到MemoryStream,然后读取它块,并从你的块中创建"小"XML数据,看起来像这样:

第一个xml:

<Root>
    <Item> some data 1 </Item>
</Root>
第二xml:

 <Root>
    <Item> some data 2 </Item>
</Root>

等等,可以单独检查并验证

当这样做时,它正在工作。

   using (MemoryStream ms = new MemoryStream())
            {
                serializer.Serialize(ms, data);
                ms.Position = 0;
                XmlReader reader = XmlReader.Create(ms, schemaReaderSettings);
            }
相关文章:
  • 没有找到相关文章