c# - 什么是替代 BinaryFormatter 的良好内存保守序列化程序?

标签 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 层次结构。

因此,我更喜欢利用能够处理指向同一对象的重复指针的 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)

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

顺便说一句,我使用相同的过程尝试了下面的代码,它们没有产生异常。

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());
}

最佳答案

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

与其采用新的图形序列化器技术,这将是相当繁重的,您是否有可能减少同时序列化的类实例的数量?例如,您能否将您的对象图分解成不相连的段,然后将每个段按顺序序列化到流中? (有关如何执行此操作的教程在这里:Serializing lots of different objects into a single file。)或者您是否有一些类包含多个从不共享的小叶类,并且可以用一个代理替换所有这些类?

关于c# - 什么是替代 BinaryFormatter 的良好内存保守序列化程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25148793/

相关文章:

c# - 非序列化属性创建错误

c# - 获取 GridView 列标题文本 - 始终返回空白

.net - Teamviewer 如何使用防火墙后的直接端口共享图像

apache-spark - 如何修复 Spark Streaming Kafka Consumer 中的 "java.io.NotSerializableException: org.apache.kafka.clients.consumer.ConsumerRecord"?

c# - 将泛型类类型转换为其基类失败

c# - C# 中的 HTTP 服务器支持分块传输编码

c# - 序列化 JSON 时忽略空值

c# - foreach 循环不会遍历列表中的所有项目 - C#

c# - 从资源中添加.wav文件(WPF C#)

c# - 将控件绑定(bind)到对象是否算作订阅?