Компактная структура C # - OutOfMemoryException с XmlSerializer.Serialize - PullRequest
2 голосов
/ 28 апреля 2009

Я пытаюсь сериализовать большую коллекцию объектов (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 ]

4 голосов
/ 28 апреля 2009

Похоже, должно работать, но CF имеет непредсказуемые ограничения.

Требуется ли xml? Я не помню, чтобы он пытался сделать это с 20k-записями, но другой вариант может быть try с использованием другого сериализатора - например, 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)] и т. Д. Это также позволяет детализировать управление сериализацией (зигзаг против двойного комплимента, группировка против префикса длины и т. Д.).

0 голосов
/ 26 мая 2009

Может быть, вы могли бы рассмотреть сохранение отдельных объектов (а не сохранение коллекции как одного большого блока). Если это так, вы можете использовать проект NFileStorage, который я создал в codeplex; nfilestorage.codeplex.com (этот не предназначен специально для CF, поэтому не может сказать, совместим ли он с этим) ...

Удачи, Герт-Ян

0 голосов
/ 28 апреля 2009

Есть ли у вас показатели потребления памяти вашим приложением? Я предполагаю, что вы работаете на WM, что означает, что адресное пространство каждого процесса ограничено 32 МБ. С большим XML-кодом вполне возможно, что вам не хватает памяти.

...