あなたが暗示しているように、多くのメンバーを持つクラスがあり、多数のインスタンスがあり、計算を実行するためにそれらすべてを同時にメモリに保持する必要があると思います。
説明したクラスに対して実際に異なるサイズを取得できるかどうかを確認するために、いくつかのテストを実行しました。
オブジェクトのメモリ内サイズを見つけるために、次の簡単な方法を使用しました。
private static void MeasureMemory()
{
int size = 10000000;
object[] array = new object[size];
long before = GC.GetTotalMemory(true);
for (int i = 0; i < size; i++)
{
array[i] = new Data();
}
long after = GC.GetTotalMemory(true);
double diff = after - before;
Console.WriteLine("Total bytes: " + diff);
Console.WriteLine("Bytes per object: " + diff / size);
}
原始的かもしれませんが、このような状況ではうまく機能することがわかりました。
予想どおり、そのクラスに対してできることはほとんどありません (構造体に変換する、継承を削除する、またはメソッド属性を削除する) ことは、単一のインスタンスによって使用されるメモリに影響を与えません。メモリ使用量に関する限り、それらはすべて同等です。ただし、実際のクラスをいじって、指定されたコードで実行してみてください。
インスタンスのメモリ フットプリントを実際に削減できる唯一の方法は、データを保持するためにより小さな構造を使用することです (たとえば、long ではなく int)。多数のブール値がある場合は、それらをバイトまたは整数にグループ化し、それらを操作する単純なプロパティ ラッパーを使用できます (ブール値は 1 バイトのメモリを必要とします)。これらはほとんどの状況では重要ではないかもしれませんが、1 億個のオブジェクトの場合、ブール値を削除すると 100 MB のメモリの違いが生じる可能性があります。また、アプリケーション用に選択したプラットフォーム ターゲットが、オブジェクトのメモリ フットプリントに影響を与える可能性があることに注意してください (x64 ビルドは、x86 ビルドよりも多くのメモリを消費します)。
データのシリアル化が役立つ可能性はほとんどありません。特に複雑なクエリを実行している場合、インメモリ データベースには利点があります。ただし、データのメモリ使用量を実際に削減できる可能性はほとんどありません。残念ながら、基本的なデータ型のフットプリントを減らす方法はあまりありません。ある時点で、ファイルベースのデータベースに移行する必要があります。
ただし、ここにいくつかのアイデアがあります。これらはハッキーで、高度に条件付きであり、計算パフォーマンスが低下し、コードの保守が難しくなることに注意してください。
大規模なデータ構造では、さまざまな状態のオブジェクトで一部のプロパティのみが入力され、他のプロパティが null または既定値に設定されることがよくあります。このようなプロパティのグループを特定できる場合は、おそらくそれらをサブクラスに移動し、複数のプロパティがスペースを占有する代わりに、null になる可能性のある参照を 1 つ持つことができます。次に、必要になったときにのみサブクラスをインスタンス化します。これを残りのコードから隠すことができるプロパティ ラッパーを作成できます。ここでの最悪のシナリオでは、すべてのプロパティをメモリに保持し、さらにいくつかのオブジェクト ヘッダーとポインターを保持することになります。
おそらく、デフォルト値を取る可能性が高いメンバーをバイナリ表現に変換し、それらをバイト配列にパックすることができます。どのバイト位置がどのデータ メンバーを表しているかがわかり、それらを読み取ることができるプロパティを書き込むことができます。デフォルト値を持つ可能性が最も高いプロパティをバイト配列の末尾に配置します (たとえば、多くの場合 0 であるいくつかの long 型)。次に、オブジェクトを作成するときに、バイト配列のサイズを調整して、デフォルト値を持つプロパティをリストの最後から除外し、デフォルト値以外の値を持つ最初のメンバーに到達するまで続けます。外部コードがプロパティを要求した場合、バイト配列がそのプロパティを保持するのに十分な大きさであるかどうかを確認し、そうでない場合はデフォルト値を返すことができます。このようにして、スペースを節約できる可能性があります。最良の場合、いくつかのデータ メンバーの代わりに、バイト配列への null ポインターがあります。最悪の場合、完全なバイト配列が元のデータと同じくらいのスペースを占有し、さらに配列のオーバーヘッドが発生します。有用性は実際のデータに依存し、配列の再計算にはコストがかかるため、書き込みが比較的少ないことを前提としています。
これが役立つことを願っています:)