什么是美好的回忆保守序列化来代替的BinaryFormatter? [英] What's a good memory-conservative serializer to replace BinaryFormatter?

查看:403
本文介绍了什么是美好的回忆保守序列化来代替的BinaryFormatter?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的工作与使用使用的.Net V3.5使用C#(Visual Studio 2008中)大型应用程序的的BinaryFormatter 来创建数据文件。

 流流= File.open方法(文件路径,FileMode.Create,FileAccess.Write,FileShare.None);
BinaryFormatter的格式化=新的BinaryFormatter(NULL,(新的StreamingContext(StreamingContextStates.All,FALSE)));
formatter.Serialize(流数据);
stream.Flush();
stream.Close();
 

不幸的是,我经常得到 OutOfMemoryException异常此实现。我在寻找到的BinaryFormatter 某种另类的,我可以快速地过渡到。

值得一提的是,这个应用程序主要依赖于 ISerializable的,而不是 [Serializable接口] 属性保留版本(不爽)。此外,我们正在序列化的数据有多个变量指向同一个对象。最后,我们也序列化的列表和字典,以及,使得数据包含 ISerializable的秒。

的相当深的层次结构

因此​​,我将preFER的替代方案,需要 ISerializable.GetObjectData 能够处理重复指向同一个对象。

优势

编辑:在回答DBC,你问一个很好的问题。复制这个问题后,我得到的错误是:

 的System.OutOfMemoryException:类型System.OutOfMemoryException引发的异常。
    在System.Runtime.Serialization.ObjectIDGenerator.Rehash()
    在System.Runtime.Serialization.ObjectIDGenerator.GetId(obj对象,布尔和放大器; firstTime)
    在System.Runtime.Serialization.Formatters.Binary.ObjectWriter.InternalGetId(obj对象,布尔assignUniqueIdToValueType,类型类型,布尔和放大器; isNew)
    在System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteString(NameInfo memberNameInfo,NameInfo typeNameInfo,对象stringObject)
    在System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteKnownValueClass(NameInfo memberNameInfo,NameInfo typeNameInfo,对象数据)
    在System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteMembers(NameInfo memberNameInfo,NameInfo memberTypeNameInfo,对象memberData,WriteObjectInfo objectInfo,NameInfo typeNameInfo,WriteObjectInfo memberObjectInfo)
    在System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteMemberSetup(WriteObjectInfo objectInfo,NameInfo memberNameInfo,NameInfo typeNameInfo,字符串成员名,类型memberType,对象memberData,WriteObjectInfo memberObjectInfo)
    在System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo,NameInfo memberNameInfo,NameInfo typeNameInfo,字符串[] memberNames,类型[] memberTypes,对象[] memberData,WriteObjectInfo [] memberObjectInfos)
    在System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo,NameInfo memberNameInfo,NameInfo typeNameInfo)
    在System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(对象图,标题[] inHeaders,__BinaryWriter serWriter,布尔FCHECK)
    在System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(流serializationStream,对象图,标题[]头,布尔FCHECK)
    在System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(流serializationStream,对象图)
 

快速谷歌搜索告诉我,这是由于序列化对象太大。我是pretty的肯定我不会像存储图像或音频任何二进制信息,所以这令我有些奇怪。我的猜测是,也许一个列表偏大序列化。

顺便说一下,我试图code以下,使用相同的步骤,并且它们不产生异常。

 的SerializationInfo信息=新的SerializationInfo(typeof运算(数据),新FormatterConverter());
的StreamingContext上下文=新的StreamingContext(StreamingContextStates.All,假);
data.GetObjectData(信息,上下文);
的foreach(在信息SerializationEntry E)
{
    的Debug.WriteLine(姓名:+ e.Name);
    的Debug.WriteLine(类型:+ e.ObjectType.ToString());
    的Debug.WriteLine(价值:+ e.Value.ToString());
}
 

解决方案

这是特别不引发异常,因为你是序列化对象太大。它被抛出,因为你是一个序列化对象图有这么多的对象的<一个href="http://referencesource.microsoft.com/#mscorlib/system/runtime/serialization/objectidgenerator.cs"><$c$c>ObjectIDGenerator在<一个href="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter%28v=vs.110%29.aspx"><$c$c>BinaryFormatter无法分配足够大的哈希表来分配唯一的ID给每个指针。串行器使用 ObjectIDGenerator 来产生一个运行时间序列,以便正确地作为一个单一的基于身份的间接引用序列化多次引用同一个类实例的每个引用类的唯一ID 。任何图形序列化,你选择需要做这样的事情。

而不是采用新的图形序列化技术,这将是相当沉重的负担,有可能为您降低类实例的同时,你的序列号?例如,你可以把你的对象图到断开段,每一个进入顺序流序列化? (关于如何做到这一点的教程是在这里:序列化许多不同的对象成单个文件。),或者你有一些类,包括那些从来不共用,并可能被替换为所有这些单个代理多个小叶类?

I'm working with a large application using .Net v3.5 with C# (Visual Studio 2008) that uses the BinaryFormatter to create a data file.

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

Unfortunately, I frequently get OutOfMemoryException from this implementation. I'm looking for some sort of alternative to BinaryFormatter that I can quickly transition to.

It's worth noting that this application mostly relies on ISerializable, rather than [Serializable] attributes to retain versioning (of sorts). Additionally, the data we're serializing has multiple variables that points to the same object. Lastly, we also serialize Lists and Dictionaries as well, making the data contain a rather deep hierarchy of ISerializables.

Thus, I would prefer an alternative that takes advantage of ISerializable.GetObjectData capable of handling repeating pointers to the same object.

Edit: in reply to dbc, you ask a very good question. After replicating the issue, the error I get is:

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 tells me that this is due to serializing an object that is too large. I'm pretty sure I'm not storing any binary information like images or audio, so this strikes me as a little strange. My guess would be that perhaps a list is too large to serialize.

Incidentally, I tried the code below using the same procedure, and they don't produce an exception.

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

解决方案

That particular exception isn't thrown because you are serializing an object that is too large. It is thrown because you are serializing an object graph with so many objects that the ObjectIDGenerator inside BinaryFormatter cannot allocate a large enough hash table to assign unique IDs to each pointer. The serializer uses ObjectIDGenerator to generate a run-time unique ID for each reference class serialized so as to correctly serialize multiple references to the same class instance as a single id-based indirect reference. Any graph serializer you choose will need to do something like this.

Rather than adopting a new graph serializer technology, which will be quite burdensome, is it possible for you to reduce the number of class instances you serialize simultaneously? For instance, can you break your object graph into disconnected segments, and serialize each one sequentially into the stream? (One tutorial on how to do this is here: Serializing lots of different objects into a single file.) Or do you have some classes that contain multiple small leaf classes that are never shared and could be replaced with a single proxy for all of them?

这篇关于什么是美好的回忆保守序列化来代替的BinaryFormatter?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆