23

.NET DataTable およびテーブル内の個々の DataRows に関連するメモリ オーバーヘッドの量を把握しようとしています。
言い換えれば、データテーブルは、データの各列の適切に型付けされた配列を単に格納するために必要なメモリよりもどれだけ多くのメモリを占有するでしょうか?
基本的なテーブルのオーバーヘッドに加えて、列ごとにいくらかの量があり、さらに行ごとに追加の量があると思います。

では、これら 3 種類のオーバーヘッドのそれぞれについて、誰かが見積もり (そして、おそらく説明も!) できるでしょうか?

4

3 に答える 3

23

DataTableさて、店舗2であることを忘れないでください。3? データのバージョン - 元のバージョンと更新されたバージョン (おそらく別のバージョン?)。また、セルベースであるため、多くの参照があり、任意の値タイプのボックス化が行われます。正確なメモリを定量化するのは難しいでしょう...

個人的には、私はめったに使用しませんDataTable- 型付けされた POCO クラスは、私の見解でははるかに賢明な賭けです。ただし、配列を(直接)使用することはありません-List<T>またはBindingList<T>同様の方法がはるかに一般的です。

大まかな尺度として、多くのテーブルなどを作成してメモリ使用量を調べることができます。たとえば、次の例では最大 4.3 の係数が示されています。つまり、4 倍以上のコストがかかりますが、これは明らかに、列数、行数、テーブル数などに大きく依存します。

    // takes **roughly** 112Mb  (taskman)
    List<DataTable> tables = new List<DataTable>();
    for (int j = 0; j < 5000; j++)
    {
        DataTable table = new DataTable("foo");
        for (int i = 0; i < 10; i++)
        {
            table.Columns.Add("Col " + i, i % 2 == 0 ? typeof(int)
                                : typeof(string));
        }
        for (int i = 0; i < 100; i++)
        {
            table.Rows.Add(i, "a", i, "b", i, "c", i, "d", i, "e");
        }
        tables.Add(table);
    }
    Console.WriteLine("done");
    Console.ReadLine();

    // takes **roughly** 26Mb (taskman)
    List<List<Foo>> lists = new List<List<Foo>>(5000);
    for (int j = 0; j < 5000; j++)
    {
        List<Foo> list = new List<Foo>(100);
        for (int i = 0; i < 100; i++)
        {
            Foo foo = new Foo { Prop1 = "a", Prop3 = "b",
                 Prop5 = "c", Prop7 = "d", Prop9 = "e"};
            foo.Prop0 = foo.Prop2 = foo.Prop4 = foo.Prop6 = foo.Prop8 = i;
            list.Add(foo);
        }
        lists.Add(list);
    }
    Console.WriteLine("done");
    Console.ReadLine();

(に基づく)

class Foo
{
    public int Prop0 { get; set; }
    public string Prop1 { get; set; }
    public int Prop2 { get; set; }
    public string Prop3 { get; set; }
    public int Prop4 { get; set; }
    public string Prop5 { get; set; }
    public int Prop6 { get; set; }
    public string Prop7 { get; set; }
    public int Prop8 { get; set; }
    public string Prop9 { get; set; }
}
于 2009-01-08T15:25:35.187 に答える
8

列にインデックスを定義しない場合、オーバーヘッドはかなり低くなります。文字列キャッシュを使用すると、メモリ フットプリントをかなり低くすることができます。HashSet または Dictionary を使用して、すべての文字列値の 1 つの文字列インスタンスのみを使用します。これは奇妙に聞こえるかもしれませんが、データベースからデータをフェッチし、同じ文字列値 (たとえば "ALFKI") を持つ複数の行がある場合、文字列値は同じですが、文字列インスタンスは等しくありません: 文字列は複数回格納されますメモリー。重複するインスタンスを除外するために最初に HashSet を使用する場合、データテーブル内のどこでも 1 つの文字列値に対して同じ文字列インスタンスを効果的に使用します。これにより、メモリ フットプリントを大幅に削減できます。もちろん、文字列値がすでにどこかで静的に定義されている場合 (外部ソースから読み取られない場合) は、努力する価値はありません。

于 2009-01-08T15:29:31.157 に答える
4

保存するデータの量と種類によって異なります。明らかに、データが多いほど、メモリも多くなります。データテーブルに関連するオーバーヘッドがあり、少し高価になります。ラージ オブジェクト ヒープにも注意する必要があります。85 kb を超えるオブジェクトを保存すると、オブジェクトは LOH に保存されます。これは完全なコレクションを必要とするため、ガベージ コレクションに大混乱をもたらす可能性があります。テストする場合は、メモリ プロファイラを調べて、データ テーブルのメモリ フットプリントを確認してください。

于 2009-01-08T15:31:03.710 に答える