系统.在使用DataContractSerializer序列化对象后调用MemoryStream.ToArray()时出
本文关键字:MemoryStream 调用 ToArray 时出 对象 DataContractSerializer 序列化 系统 | 更新日期: 2023-09-27 18:02:03
我在这个语句中得到一个间歇性的"内存不足"异常:
return ms.ToArray();
在此方法中:
public static byte[] Serialize(Object inst)
{
Type t = inst.GetType();
DataContractSerializer dcs = new DataContractSerializer(t);
MemoryStream ms = new MemoryStream();
dcs.WriteObject(ms, inst);
return ms.ToArray();
}
如何预防?有更好的方法吗?
ms的长度为182,870,206字节(174.4 MB)
我把它放入一个字节数组,这样我就可以通过压缩运行它并将其存储到磁盘上。这些数据(显然)是我在启动silverlight应用程序时从WCF服务器下载的一个自定义类的大列表。我正在序列化它并压缩它,所以它在独立存储中只使用了大约6MB。下次用户从web访问并运行silverlight应用程序时,我检查时间戳,如果正确,我就从隔离中打开文件,解压缩它,反序列化它,并加载我的结构。我将整个结构体保存在内存中,因为应用程序主要是围绕着操作该结构体的内容。
@configurator是正确的。数组的大小太大。我通过自己的序列化器滚动,通过声明一个字节数组[list record count *每条记录的字节计数],然后自己直接填充它,使用下面的语句填充它:
Buffer.BlockCopy(
BitConverter.GetBytes(node.myInt),0,destinationArray,offset,sizeof(int));
offset += sizeof(int);
和这个来把它拿回来:
newNode.myInt= BitConverter.ToInt32(sourceByteArray,offset);
offset += sizeof(int);
然后我将其压缩并存储到单独的存储中。
我的大小从使用DataContractSerializer时的174MB变为使用我的14MB。压缩后,它从一个6MB的文件变成了一个1MB的文件。
感谢Configurator和Filip的帮助
问题似乎是您期望返回180MB字节数组。这意味着框架需要找到并分配连续180MB的空闲内存来将流数据复制到其中,这通常是相当困难的——因此出现了OutOfMemoryException。如果你需要继续处理这个数量的内存,使用内存流本身(根据需要对其进行读写)来保存缓冲区;否则,直接将其保存到文件(或任何其他你需要它的地方,例如通过网络提供),而不是使用内存流。
我应该提到的是,内存流本身也有一个180MB的数组,所以在序列化过程中也会遇到一些麻烦,可能会导致OutOfMemory——如果您可以将它序列化到一个临时文件中,可能会更好(也就是说,更健壮)。您可能还想考虑一种更紧凑(但可能可读性较差)的序列化格式,如json、二进制序列化或协议缓冲区。
回应评论:要直接序列化到磁盘,请使用FileStream
而不是MemoryStream
:
public static void Serialize(Object inst, string filename)
{
Type t = inst.GetType();
DataContractSerializer dcs = new DataContractSerializer(t);
using (FileStream stream = File.OpenWrite(filename)) {
dcs.WriteObject(ms, inst);
}
}
我不知道你是如何使用这些代码的,但有一件事让我印象深刻,那就是你没有释放你的资源。例如,如果你用大量的大对象调用Serialize(obj)
很多次,你最终会有很多内存被使用,而不是直接释放,然而GC
应该正确处理,但你应该总是释放你的资源。
我试过这段代码:
public static byte[] Serialize(object obj)
{
Type type = obj.GetType();
DataContractSerializer dcs = new DataContractSerializer(type);
using (var stream = new MemoryStream())
{
dcs.WriteObject(stream, obj);
return stream.ToArray();
}
}
在控制台应用程序中使用以下Main
-方法
static void Main(string[] args)
{
var filipEkberg = new Person {Age = 24, Name = @"Filip Ekberg"};
var obj = Serialize(filipEkberg);
}
然而,我的byte
-数组几乎没有你的那么大。看看这个类似的问题,您可能会考虑查看protobuf-net。
它也可能是有趣的知道你打算做什么序列化的数据,你需要它作为一个byte
数组,或者它也可以是XML写入一个文本文件?
尝试序列化为流(即FileStream)而不是字节数组。这样就可以序列化千兆字节的数据,而不会出现OutOfMemory异常。
public static void Serialize<T>(T obj, string path)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
Stream stream = File.OpenWrite(path);
serializer.WriteObject(stream, obj);
}
public static T Deserialize<T>(string path)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
Stream stream = File.OpenRead(path);
return (T)serializer.ReadObject(stream);
}
尝试将内存流位置设置为0,然后只调用ToArray()。
问候。