什么是一个很好的内存保守序列化器来取代BinaryFormatter?

时间:2014-08-05 21:38:11

标签: c# .net serialization

我正在使用.Net v3.5和C#(Visual Studio 2008)使用BinaryFormatter来创建数据文件的大型应用程序。

Stream stream = File.Open(filePath, FileMode.Create, FileAccess.Write, FileShare.None);
BinaryFormatter formatter = new BinaryFormatter(null, (new StreamingContext(StreamingContextStates.All, false)));
formatter.Serialize(stream, data);
stream.Flush();
stream.Close();

不幸的是,我经常从这个实现中获得OutOfMemoryException。我正在寻找BinaryFormatter的某种替代方案,我可以快速转换到这种方式。

值得注意的是,此应用程序主要依赖于ISerializable而非[Serializable]属性来保留版本控制(各种类型)。此外,我们要序列化的数据有多个指向同一对象的变量。最后,我们还将列表和字典序列化,使数据包含相当深的ISerializable s层次结构。

因此,我更喜欢使用能够处理同一对象重复指针的ISerializable.GetObjectData的替代方案。

编辑:在回复dbc时,你会问一个非常好的问题。复制问题后,我得到的错误是:

System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
    at System.Runtime.Serialization.ObjectIDGenerator.Rehash()
    at System.Runtime.Serialization.ObjectIDGenerator.GetId(Object obj, Boolean& firstTime)
    at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.InternalGetId(Object obj, Boolean assignUniqueIdToValueType, Type type, Boolean& isNew)
    at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteString(NameInfo memberNameInfo, NameInfo typeNameInfo, Object stringObject)
    at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteKnownValueClass(NameInfo memberNameInfo, NameInfo typeNameInfo, Object data)
    at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteMembers(NameInfo memberNameInfo, NameInfo memberTypeNameInfo, Object memberData, WriteObjectInfo objectInfo, NameInfo typeNameInfo, WriteObjectInfo memberObjectInfo)
    at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteMemberSetup(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo, String memberName, Type memberType, Object memberData, WriteObjectInfo memberObjectInfo)
    at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo, String[] memberNames, Type[] memberTypes, Object[] memberData, WriteObjectInfo[] memberObjectInfos)
    at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
    at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
    at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
    at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)

快速谷歌搜索告诉我,这是由于序列化一个太大的对象。我很确定我没有存储任何二进制信息,如图像或音频,所以这让我有点奇怪。我的猜测可能是列表太大而无法序列化。

顺便说一句,我使用相同的程序尝试了下面的代码,但它们不会产生异常。

SerializationInfo info = new SerializationInfo(typeof(Data), new FormatterConverter());
StreamingContext context = new StreamingContext(StreamingContextStates.All, false);
data.GetObjectData(info, context);
foreach (SerializationEntry e in info)
{
    Debug.WriteLine("Name: " + e.Name);
    Debug.WriteLine("Type: " + e.ObjectType.ToString());
    Debug.WriteLine("Value: " + e.Value.ToString());
}

1 个答案:

答案 0 :(得分:10)

由于您要序列化太大的对象,因此不会引发该特定异常。抛出它是因为您正在序列化具有如此多对象的对象图,ObjectIDGenerator内的BinaryFormatter无法分配足够大的哈希表来为每个指针分配唯一ID。序列化程序使用ObjectIDGenerator为序列化的每个引用类生成运行时唯一ID,以便正确序列化对同一类实例的多个引用作为单个基于id的间接引用。您选择的任何图形序列化程序都需要执行以下操作。

您可以减少同时序列化的类实例的数量,而不是采用一种非常繁琐的新图形序列化器技术吗?例如,您是否可以将对象图断开为断开的段,并将每个段顺序序列化为流? (关于如何执行此操作的一个教程是:Serializing lots of different objects into a single file。)或者您是否有一些类包含多个从未共享的小叶类,并且可以用所有这些类的单个代理替换?