40

比較的複雑な (ゲーム) オブジェクト構造のファイルに状態情報を格納するための一時的なメカニズムとして、バイナリ シリアル化 (BinaryFormatter) を使用しています。ファイルが予想よりもはるかに大きくなり、データ構造に再帰参照が含まれているため、BinaryFormatter が実際に同じオブジェクトの複数のコピーを格納しているのか、それとも基本的な「オブジェクトと値の数が必要か」 " 算術はベースから外れているか、または過度のサイズがどこから来ているのか.

スタック オーバーフローを検索すると、Microsoft のバイナリ リモーティング形式の仕様を見つけることができました: http://msdn.microsoft.com/en-us/library/cc236844(PROT.10).aspx

私が見つけられないのは、binaryformatter 出力ファイルの内容を「覗く」ことができる既存のビューアーです。ファイル内のさまざまなオブジェクト タイプのオブジェクト数と合計バイト数を取得するなど。

これは私の「google-fu」が私を失敗させているに違いないと感じています(私が持っているものはほとんどありません)-誰か助けてもらえますか?これは以前に行われたに違いありませんよね??


更新:私はそれを見つけることができず、答えが得られなかったので、比較的簡単にまとめました(以下のダウンロード可能なプロジェクトへのリンク)。BinaryFormatter が同じオブジェクトの複数のコピーを保存していないことを確認できますが、かなりの数のメタデータをストリームに出力します。効率的なストレージが必要な場合は、独自のカスタム シリアル化メソッドを構築します。

4

4 に答える 4

7

Vasiliy は、バージョン管理をより適切に処理し、(圧縮前に) よりコンパクトなストリームを出力するために、最終的に独自のフォーマッタ/シリアル化プロセスを実装する必要があるという点で正しいです。

ただし、ストリームで何が起こっているのかを理解したかったので、必要なことを行う (比較的) クイックなクラスを作成しました。

  • ストリームを介してその方法を解析し、オブジェクト名、カウント、およびサイズのコレクションを構築します
  • 完了すると、ストリーム内のクラス、カウント、合計サイズなど、見つかったものの簡単な要約を出力します

codeproject のように見える場所に置くだけでは役に立たないので、プロジェクトを自分の Web サイトの zip ファイルにダンプしました: http://www.architectshack.com/BinarySerializationAnalysis.ashx

私の特定のケースでは、問題は 2 つであることがわかりました。

  • BinaryFormatter は非常に冗長です (これはわかっていますが、その範囲を認識していませんでした)。
  • クラスに問題がありました。不要なオブジェクトを保存していたことが判明しました

これがいつか誰かに役立つことを願っています!


更新: Ian Wright から、元のコードの問題について連絡がありました。ソース オブジェクトに「10 進数」の値が含まれているとクラッシュしました。これは現在修正されており、この機会を利用してコードを GitHub に移動し、(permissive、BSD) ライセンスを付与しました。

于 2010-06-19T18:21:03.077 に答える
5

私たちのアプリケーションは大量のデータを操作します。ゲームと同様に、最大 1 ~ 2 GB の RAM を使用できます。同じ「同じオブジェクトの複数のコピーを保存する」問題に遭遇しました。また、バイナリ シリアライゼーションではメタデータが多すぎます。最初に実装されたとき、シリアル化されたファイルは約 1 ~ 2 GB かかりました。最近では、値を50〜100 MBに減らすことができました。私たちは何をしましたか。

短い答え - .Net バイナリ シリアライゼーションを使用せず、独自のバイナリ シリアライゼーション メカニズムを作成します。独自の BinaryFormatter クラスと ISerializable インターフェイス (Serialize、Deserialize の 2 つのメソッドを持つ) があります。

同じオブジェクトを複数回シリアル化しないでください。一意の ID を保存し、オブジェクトをキャッシュから復元します。

質問があれば、いくつかのコードを共有できます。

編集:あなたは正しいようです。次のコードを見てください - それは私が間違っていたことを証明しています.

[Serializable]
public class Item
{
    public string Data { get; set; }
}

[Serializable]
public class ItemHolder
{
    public Item Item1 { get; set; }

    public Item Item2 { get; set; }
}

public class Program
{
    public static void Main(params string[] args)
    {
        {
            Item item0 = new Item() { Data = "0000000000" };
            ItemHolder holderOneInstance = new ItemHolder() { Item1 = item0, Item2 = item0 };

            var fs0 = File.Create("temp-file0.txt");
            var formatter0 = new BinaryFormatter();
            formatter0.Serialize(fs0, holderOneInstance);
            fs0.Close();
            Console.WriteLine("One instance: " + new FileInfo(fs0.Name).Length); // 335
            //File.Delete(fs0.Name);
        }

        {
            Item item1 = new Item() { Data = "1111111111" };
            Item item2 = new Item() { Data = "2222222222" };
            ItemHolder holderTwoInstances = new ItemHolder() { Item1 = item1, Item2 = item2 };

            var fs1 = File.Create("temp-file1.txt");
            var formatter1 = new BinaryFormatter();
            formatter1.Serialize(fs1, holderTwoInstances);
            fs1.Close();
            Console.WriteLine("Two instances: " + new FileInfo(fs1.Name).Length); // 360
            //File.Delete(fs1.Name);
        }
    }
}

BinaryFormatterobject.Equals を使用して同じオブジェクトを検索しているようです。

生成されたファイルの中を見たことがありますか? コード例の「temp-file0.txt」と「temp-file1.txt」を開くと、大量のメタデータが含まれていることがわかります。そのため、独自のシリアル化メカニズムを作成することをお勧めします。

混乱してすみません。

于 2010-06-16T10:34:38.633 に答える
-1

プログラムをデバッグ モードで実行し、コントロール ポイントを追加してみてください。

ゲームのサイズやその他の依存関係のためにそれが不可能な場合は、逆シリアル化コードを含む単純な/小さなアプリをいつでもコーディングして、そこでデバッグ モードから覗くことができます。

于 2010-06-16T10:35:22.500 に答える