LOHにはいくつかの機能があります。
- LOHのオブジェクトは移動しません
- LOHは成長するだけで、決して減少しません(つまり、オブジェクトがガベージコレクターによって収集される場合、LOHサイズは変更されません)
- ヒップLOHは、LOHが完全に空の場合にのみリリースされます
LOHのこれら2つの機能のうち、忘れられがちな2つの重要な結果があります。
- LOHメモリが断片化する場合があります。 つまり 管理されていない世界で戦った何かが起こります:ある時点で10Mbの空きメモリがあるかもしれませんが、1Mbサイズのオブジェクトにメモリを割り当てることはできません
- 一度大きなオブジェクトにメモリを割り当ててから、小さなオブジェクトのみを使用すると、実際には大きなメモリチャンクが奪われます。 さらに、LOHにサイズNのリストまたはハッシュテーブルがあり、それに1つの要素を追加した場合、リストは実現して倍になるため、LOHのサイズは少なくとも3 * N(Nは初期データ、2N -データのコピーと新しいサイズの予約。 次の成長では、LOHに4 * Nの連続したサイズのメモリが必要になります。LOHにはそのようなピースがないため(Nのみ)、プロセスのアドレススペースから借用する必要があります。 その結果、LOHサイズは7 * Nに増加します。
LOHが16Mbのチャンクによって割り当てられていることを思い出せば、発生するすべてのことはさらに破壊的に見えるでしょう。 最初の結果は、オブジェクトを使用して慎重に制御できます。 第二-大型オブジェクトを使用せずに。 特に大きなコレクションで作業したい場合は特にそうです。 この問題を解決する方法を見てみましょう。
チャンクのコンテナ実装
コンテナをチャンクakに実装してみることができます(つまり、アレイ全体ではなく、LOHに分類されない小さな部分にメモリを割り当てます)。 さらに、
IList<T>
を実装するチャンクのみの必要性を直接行う必要があり、他のすべてのコンテナはデータのストレージとして
IList<T>
を使用し
IList<T>
。
次のリストの実装を始めましょう。
public class ChunkList<T> : IList<T>
{
private readonly int _ChunkSize = 4096;
private int _Count;
private T[][] _Chunks;
}
* This source code was highlighted with Source Code Highlighter .
_Chunks
では、それぞれに
_ChunkSize
オブジェクトによって
N
ページを保存し、新しいページを動的に削除または追加します。 実際には、宿題として実装自体を私の希望に任せます。 それほど複雑ではなく、すべての操作を慎重に記述する必要があります。
しかし、私が引用したコードにはすでにエラーがあります。
_ChunkSize
デフォルト値のエラー。 実際、この値は参照型には適していますが、構造体には適していません。 結局、構造体は
_Chunks
配列のデータと同じ量のメモリを占有します。 そのため、何らかの方法でデータ型
T
サイズを調べ、チャンクの数を
85000/sizeof(T)
としてカウントする必要があります。 しかし、見かけの単純さにもかかわらず、このタスクは簡単に解決できません。
「 構造のサイズの計算」という記事に目を向けると、 サイズを見つける問題の解決策を見つけることができます。
public static int GetSize<T>()
{
Type tt = typeof (T);
int size;
if (tt.IsValueType)
{
if (tt.IsGenericType)
{
var t = default (T);
size = Marshal.SizeOf(t);
}
else
{
size = Marshal.SizeOf(tt);
}
}
else
{
size = IntPtr .Size;
}
return size;
}
* This source code was highlighted with Source Code Highlighter .
したがって、
ChunkList
を補足できます。
public class ChunkList<T> : IList<T>
{
static ChunkList()
{
_ChunkSize = 80000 / GetSize<T>();
}
private static readonly int _ChunkSize = 4096;
private int _Count;
private T[][] _Chunks;
}
* This source code was highlighted with Source Code Highlighter .
すべては問題ありませんが、このコードが構造体のインスタンスを作成するのは(まれに)場合によってのみです。 問題がなければ、そのままにしておくことができます。 重要な場合は、リストの各ユーザーがオブジェクトのサイズまたはチャンクの目的のサイズを個別に転送できるコンストラクターを作成する必要があります。
大きなオブジェクトをどのように扱いますか?