【问题标题】:C# Compact Framework - OutOfMemoryException with XmlSerializer.SerializeC# 精简框架 - 带有 XmlSerializer.Serialize 的 OutOfMemoryException
【发布时间】:2009-05-26 15:07:40
【问题描述】:

我正在尝试序列化集合中的大量对象(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;

有没有更好的方法来做到这一点,还是我做错了什么?

【问题讨论】:

  • 感谢指标更新 - 非常感谢。这些时间安排令人满意吗?作为信息,它在 CF 3.5 上再次更快,因为它可以使用 Delegate.CreateDelegate 来优化属性访问。
  • 不,谢谢,它要快得多。使用 XmlSerializer 处理 20000 条记录需要 3 分 50 秒。

标签: c# serialization compact-framework stringwriter


【解决方案1】:

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

xml 是必需的吗?我不记得用 20k 条记录尝试过,但另一种选择可能是 try 使用不同的序列化程序 - 例如,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,分组 vs 长度前缀等)。

【讨论】:

  • 只是补充一点,感谢 Protobuf.Net,我现在正在序列化,然后在 29 秒内将 20,000 条记录(在我最大的表结构中)保存到一个文件中。然后我可以在 28 秒内使用反序列化器加载该文件)。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    祝你好运, 格特扬

    【讨论】:

    • 如果您知道您的项目与 CF 一起使用,那么我对您提供它作为解决方案没有任何问题,但如果您不知道,请不要发布它希望能简单地提高曝光率。自己测试场景,如果可行然后告诉我们。
    猜你喜欢
    • 1970-01-01
    • 2011-12-13
    • 1970-01-01
    • 1970-01-01
    • 2014-06-06
    • 2013-01-28
    • 1970-01-01
    • 2022-11-08
    • 2016-06-20
    相关资源
    最近更新 更多