メモリ:LOHおよびチャンクリスト

.Netの管理メモリは、スタックといくつかのヒープに分割されます。 ヒップの中で最も重要なのは、通常の(一時的な)ヒープとLOHです。 はかないヒープは、すべての普通のオブジェクトが存在する場所です。 LOHは、大きな(85,000バイトを超える)オブジェクトが存在する場所です。

LOHにはいくつかの機能があります。

LOHのこれら2つの機能のうち、忘れられがちな2つの重要な結果があります。


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 .


すべては問題ありませんが、このコードが構造体のインスタンスを作成するのは(まれに)場合によってのみです。 問題がなければ、そのままにしておくことができます。 重要な場合は、リストの各ユーザーがオブジェクトのサイズまたはチャンクの目的のサイズを個別に転送できるコンストラクターを作成する必要があります。

大きなオブジェクトをどのように扱いますか?

Source: https://habr.com/ru/post/J83929/


All Articles