2009-04-28 14 views
2

コレクション内のオブジェクト(20,000)の大きなコレクションをシリアル化しようとしています。私は、次のコードを使用して、これをやっている:C#Compact Framework - XmlSerializer.Serializeを使用したOutOfMemoryException

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

おかげで - 感謝。そのタイミングは満足いくものですか?情報の場合は、Delegate.CreateDelegateを使用してプロパティのアクセスを最適化できるため、CF 3.5では再び高速になります。 –

+0

いいえ、ありがとう、ずっと速いです。 XmlSerializerを使用すると、20000レコードに対して3分50秒かかります。 – GenericTypeTea

答えて

4

になるはずですが、CFには予測できない制限があります。

xmlは必須ですか? 20kのレコードで試してみるのは覚えていませんが、もう1つの選択肢はで、別のシリアライザを使ってみてください。たとえば、protobuf-netがCF2で動作します。私はそれが動作することを保証することはできませんが、それはショットの価値があるかもしれません。

(特に、私は現在、CF内でさらに"generics" limitationsを回避するためにコードをリファクタリングしていますが、非常に複雑なオブジェクトモデルを使用しない限り、これはあなたには影響しません)。


使用例。この例はまた、XmlSerializerのために[OK]を動作しますが、いるProtobufネットの使用は、スペースのわずか20%(あなたは文字がメモリ内の2バイトの各していることやスペースの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)]などを使用しました。これにより、シリアル化の細かい制御(ジグザグvs twoscompliment、グループ化vs長さ接頭辞など)も可能になります。

+0

ProtoBufの使い方の良い例はありますか? – GenericTypeTea

+1

1個追加できます... –

+0

ありがとうございます! – GenericTypeTea

0

アプリケーションのメモリ消費量に関するメトリックはありますか?私はあなたがWM上で動作していると仮定しています。つまり、各プロセスのアドレス空間は32MBに制限されています。大規模なXMLでは、実際にはメモリ不足の可能性があります。

0

おそらく、コレクションを1つの大きなブロックとして維持するのではなく、個々のオブジェクトを永続化することを検討できます。もしそうなら、私がcodeplexで作成したNFileStorageプロジェクトを使用したいかもしれません。 nfilestorage.codeplex.com(この1つは、特にCFのために作られていないので、その1とその互換性の場合には言うことができない)...

幸運、 ゲルト・ヤンメトリックの更新のための

+1

あなたのプロジェクトがCFで動作することを知っていれば、ソリューションとして提供することに問題はありませんが、わからないのであれば簡単に露出を増やすことを期待して投稿しないでください。シナリオを自分でテストし、それが機能している場合は*私たちにお知らせください。 – ctacke

関連する問題