C#Compact Framework - 使用XmlSerializer.Serialize的OutOfMemoryException

时间:2009-04-28 07:56:49

标签: c# serialization compact-framework stringwriter

我正在尝试序列化集合中的大量对象(20,000)对象。我正在使用以下代码执行此操作:

XmlSerializer xs = new XmlSerializer(deserialized.GetType());
StringWriter sw;
using (sw = new StringWriter())
{
   xs.Serialize(sw, deserialized);   // OutOfMemoryException here
}

string packet = sw.ToString();
return packet;

有更好的方法可以做到这一点,还是我做了一些公然错误的事情?

3 个答案:

答案 0 :(得分:4)

看起来应该工作,但CF确实有不可预测的限制。

xml是否需要?我不记得尝试使用20k记录,但另一种选择可能是尝试使用不同的序列化程序 - 例如,protobuf-net适用于CF2。我不能保证它会起作用,但它可能值得一试。

(特别是,我正在重构代码以尝试在CF中解决一些额外的"generics" limitations - 除非你有一个非常复杂的对象模型,否则这不会影响你。)


显示用法的示例;请注意,此示例也适用于XmlSerializer,但protobuf-net仅使用20%的空间(如果您认为每个字符在内存中的两个字节,则占空间的10%):

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using ProtoBuf;

[Serializable, ProtoContract]
public class Department
{
    [ProtoMember(1)]
    public string Name { get; set; }
    [ProtoMember(2)]
    public List<Person> People { get; set; }
}

[Serializable, ProtoContract]
public class Person
{
    [ProtoMember(1)]
    public int Id { get; set; }
    [ProtoMember(2)]
    public string Name { get; set; }
    [ProtoMember(3)]
    public DateTime DateOfBirth { get; set; }
}


static class Program
{
    [MTAThread]
    static void Main()
    {
        Department dept = new Department { Name = "foo"};
        dept.People = new List<Person>();
        Random rand = new Random(123456);
        for (int i = 0; i < 20000; i++)
        {
            Person person = new Person();
            person.Id = rand.Next(50000);
            person.DateOfBirth = DateTime.Today.AddDays(-rand.Next(2000));
            person.Name = "fixed name";
            dept.People.Add(person);
        }

        byte[] raw;
        using (MemoryStream ms = new MemoryStream())
        {
            Serializer.Serialize(ms, dept);
            raw = ms.ToArray(); // 473,399 bytes
        }

        XmlSerializer ser = new XmlSerializer(typeof(Department));
        StringWriter sw = new StringWriter();
        ser.Serialize(sw, dept);
        string s = sw.ToString(); // 2,115,693 characters
    }
}

如果您需要更多帮助,请告诉我 - 我可以整天谈论这个主题;-p 请注意,它可以仅使用标准xml属性([XmlElement(Order=1)]) - 为了清晰起见,我使用了更具体的[ProtoMember(1)]等。这也允许对序列化进行细粒度控制(zigzag vs twoscompliment,group vs length-prefixed等)。

答案 1 :(得分:0)

您对应用程序的内存消耗有任何指标吗?我假设您正在运行WM,这意味着每个进程的地址空间限制为32MB。使用大型XML,可能实际上已经耗尽了内存。

答案 2 :(得分:0)

也许您可以考虑持久保存单个对象(而不是将集合持久化为一个大块)。如果是这样,您可能想要使用我在codeplex上创建的NFileStorage项目; nfilestorage.codeplex.com(这个不是专门针对CF制作的,所以不能判断它是否与CF兼容)...

祝你好运, 格特 - 扬