C# 紧凑框架 - 带有 XmlSerializer.Serialize 的 OutOfMemoryException

发布于 2024-07-18 17:04:39 字数 344 浏览 12 评论 0原文

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

是否有更好的方法来执行此操作,或者我做的事情明显错误?

I'm trying to serialize a large collection of objects (20,000) objects within the collection. I'm doing this using the following code:

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

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

Is there a better way of doing this, or am I doing something blatantly wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

赠我空喜 2024-07-25 17:04:39

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

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

(特别是,我目前正在重构代码以尝试解决一些额外的 CF 中的“泛型”限制 - 但除非您有一个非常复杂的对象模型,否则这不会影响您)。


显示用法的示例; 请注意,此示例对于 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)] 等为了清楚起见。 这还允许对序列化进行细粒度控制(之字形与双补、分组与长度前缀等)。

It looks like it should work, but CF does have unpredictable limitations.

Is xml a requirement? I can't remember trying it with 20k records, but another option might be to try using a different serializer - for example, protobuf-net works on CF2. I can't guarantee it'll work, but it might be worth a shot.

(in particular, I'm currently refactoring the code to try to work around some additional "generics" limitations within CF - but unless you have a very complex object model this shouldn't affect you).


Example showing usage; note that this example also works OK for XmlSerializer, but protobuf-net uses only 20% of the space (or 10% of the space if you consider that characters are two bytes each in memory):

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
    }
}

Let me know if you want more help - I can talk about this subject all day ;-p
Note that it can work just from the standard xml attributes ([XmlElement(Order=1)]) - I've used the more specific [ProtoMember(1)] etc for clarity. This also allows fine-grained control of serialization (zigzag vs twoscompliment, grouped vs length-prefixed, etc).

梦年海沫深 2024-07-25 17:04:39

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

Do you have any metrics on your application's memory consumption? I'm assuming you're running on WM, which means that each process' address space is limited to 32MB. With a large XML, it's possible that you've actually run out of memory.

梦罢 2024-07-25 17:04:39

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

祝你好运,
格特-扬

Maybe you could consider persisting the individual objects (rather than persisting the collection as one big block). If so, you might want to use the NFileStorage project I created on codeplex; nfilestorage.codeplex.com (this one is not specifically made for the CF, so cannot tell if its compatible with that one)...

Good luck,
Gert-Jan

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文