系统.在使用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的帮助

系统.在使用DataContractSerializer序列化对象后调用MemoryStream.ToArray()时出

问题似乎是您期望返回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()。

问候。