2009-04-28 4 views
2

Я пытаюсь сериализовать большую коллекцию объектов (20 000) объектов внутри коллекции. Я делаю это с помощью следующего кода:C# Compact Framework - OutOfMemoryException с XmlSerializer.Serialize

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

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

Есть ли лучший способ сделать это, или я делаю что-то явно не так?

+1

Спасибо за обновление метрики - оценили , Являются ли эти сроки удовлетворительными? Для справки он снова работает на CF 3.5, так как он может использовать Delegate.CreateDelegate для оптимизации доступа к свойствам. –

+0

Нет, спасибо, это намного быстрее. Используя XmlSerializer, для 20000 записей требуется 3 минуты 50 секунд. – GenericTypeTea

ответ

4

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

Требуется ли xml? Я не могу вспомнить, как пробовал его с записями 20 тыс., Но другой вариант может быть попробуйте с использованием другого сериализатора - например, protobuf-net работает на CF2. Я не могу гарантировать, что это сработает, но это может стоить того.

(в частности, я в настоящее время реорганизую код, чтобы попытаться обойти некоторые дополнительные "generics" limitations внутри CF - но если у вас нет очень сложной объектной модели, это не должно повлиять на вас).


Пример использования; обратите внимание, что этот пример работает нормально для XmlSerializer, но Protobuf-сеть использует только 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

Есть ли хорошие примеры использования ProtoBuf? – GenericTypeTea

+1

Я могу добавить один ... –

+0

Спасибо! – GenericTypeTea

0

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

0

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

Успехов, Герт-Ян

+1

Если вы * знаете * ваш проект работает с CF, тогда у меня нет проблем с тем, что вы предлагаете его в качестве решения, но если вы не знаете, не публикуйте его в надежде просто управлять экспозицией. Проверьте сценарий самостоятельно, и если он работает *, тогда дайте нам знать. – ctacke

Смежные вопросы