我正在尝试将对象序列化为字符串 我遇到的第一个问题是XMLSerializer.Serialize方法抛出了内存不足异常,我尝试了所有类型的解决方案而没有工作,所以我将它序列化为一个文件。 该文件大约300mb(32位进程,8gb ram)并尝试使用StreamReader.ReadToEnd读取它也会导致内存不足异常。
XML格式并将其加载到字符串上不是必须的选项。 问题是:
.Serialize
上失败的序列化代码using (MemoryStream ms = new MemoryStream())
{
var type = obj.GetType();
if (!serializers.ContainsKey(type))
serializers.Add(type,new XmlSerializer(type));
// new XmlSerializer(obj.GetType()).Serialize(ms, obj);
serializers[type].Serialize(ms, obj);
ms.Position = 0;
using (StreamReader sr = new StreamReader(ms))
{
return sr.ReadToEnd();
}
}
序列化并从ReadToEnd上失败的文件中读取 var type = obj.GetType(); if(!serializers.ContainsKey(type)) serializers.Add(type,new XmlSerializer(type));
FileStream fs = new FileStream(@"c:/temp.xml", FileMode.Create);
TextWriter writer = new StreamWriter(fs, new UTF8Encoding());
serializers[type].Serialize(writer, obj);
writer.Close();
fs.Close();
using (StreamReader sr = new StreamReader(@"c:/temp.xml"))
{
return sr.ReadToEnd();
}
对象很大,因为它是一个精心设计的系统整个配置对象......
更新: 在chucks中读取文件(8 * 1024个字符)会将文件加载到StringBuilder中,但构建器在ToString()上失败....开始认为没有办法真的很奇怪。
答案 0 :(得分:4)
是的,如果您使用32位,尝试在一个块中加载300MB将会笨拙,尤其是在使用不知道最终大小的方法时(字符数)而不是字节),因此必须保持内部缓冲区加倍。这就是处理字符串时!然后需要将其转换为DOM,这通常需要几倍于底层数据的空间。最后,你需要将它反序列化为实际的对象,通常再次采用相同的方法。
所以 - 确实,尝试以32位方式执行此操作将非常困难。
首先要尝试的是:不要使用ReadToEnd
- 只需将XmlReader.Create
与文件路径或FileStream
一起使用,让XmlReader
担心如何使用{{1}}加载数据。不要为它加载内容。
之后......接下来要做的是:不要将其限制为32位。
好吧,你可以尝试启用3GB开关,但是......最好转移到64位。
除此之外:xml 不是大量数据的理想选择。
答案 1 :(得分:1)
探索StreamReader.ReadToEnd的源代码,发现它在内部使用了StringBuilder.Append
方法:
public override String ReadToEnd()
{
if (stream == null)
__Error.ReaderClosed();
#if FEATURE_ASYNC_IO
CheckAsyncTaskInProgress();
#endif
// Call ReadBuffer, then pull data out of charBuffer.
StringBuilder sb = new StringBuilder(charLen - charPos);
do {
sb.Append(charBuffer, charPos, charLen - charPos);
charPos = charLen; // Note we consumed these characters
ReadBuffer();
} while (charLen > 0);
return sb.ToString();
}
最有可能抛出此异常导致此问题/答案:interesting OutOfMemoryException with StringBuilder 人