ホームページ  >  記事  >  バックエンド開発  >  .Net ガベージ コレクションとラージ オブジェクトの処理

.Net ガベージ コレクションとラージ オブジェクトの処理

黄舟
黄舟オリジナル
2017-02-17 11:17:371267ブラウズ

英語の原文: Maoni Stephens、編集者: Zhao Yukai (@玉凯Sir)

CLR ガベージ コレクターは、オブジェクトが占有するスペースのサイズに応じてオブジェクトを分割します。大きなオブジェクトと小さなオブジェクトの処理方法には大きな違いがあります。たとえば、メモリのデフラグ - メモリ内の大きなオブジェクトの移動にはコストがかかります。ガベージ コレクタが大きなオブジェクトをどのように処理するか、また大きなオブジェクトがプログラムのパフォーマンスにどのような影響を与えるかを調べてみましょう。

ラージ オブジェクト ヒープとガベージ コレクション

.Net 1.0 および 2.0 では、オブジェクトのサイズが 85000 バイトを超える場合、それはラージ オブジェクトとみなされます。この数値は、パフォーマンス最適化の経験に基づいています。オブジェクトによって要求されたメモリ サイズがこのしきい値に達すると、ラージ オブジェクト ヒープに割り当てられます。これはどういう意味ですか?これを理解するには、.Net ガベージ コレクション メカニズムを理解する必要があります。

ほとんどの人が知っているように、.Net GC は「世代」単位でデータを収集します。プログラムには、世代 0、世代 1、および世代 2 の 3 つの世代のオブジェクトがあります。世代 0 が最も若いオブジェクトで、世代 2 のオブジェクトの生存時間が最も長くなります。 GC はパフォーマンス上の理由から世代ごとにガベージを収集します。通常、オブジェクトは世代 0 でリサイクルされます。たとえば、ASP.NET プログラムでは、各要求に関連付けられたオブジェクトは要求の最後にリサイクルされる必要があります。リサイクルされていないオブジェクトは第 1 世代のオブジェクトになります。つまり、第 1 世代のオブジェクトは、常駐メモリ オブジェクトと、もうすぐ消滅するオブジェクトとの間のバッファになります。

世代の観点から見ると、大きなオブジェクトは第 2 世代のリサイクル中にのみ処理されるため、大きなオブジェクトは第 2 世代のオブジェクトに属します。ある世代のガベージコレクションが実行されると、それよりも若い世代のガベージコレクションも同時に実行されます。例: 第 1 世代のガベージ コレクションが実行されると、第 1 世代と第 0 世代のオブジェクトが同時にリサイクルされます。第 2 世代のガベージ コレクションが実行されると、第 1 世代と第 0 世代のオブジェクトがリサイクルされます。

Generation は、メモリ領域を区別するためのガベージ コレクターの論理ビューです。物理ストレージの観点から見ると、オブジェクトはさまざまなマネージド ヒープに割り当てられます。マネージド ヒープは、オペレーティング システムからガベージ コレクターによって (Windows API VirtualAlloc を呼び出して) 割り当てられるメモリ領域です。 CLR がメモリをロードすると、ラージ オブジェクト ヒープ (LOH – ラージ オブジェクト ヒープ) とスモール オブジェクト ペア (SOH – スモール オブジェクト ヒープ) の 2 つのマネージド ヒープが初期化されます。

メモリ割り当てリクエストは、マネージド オブジェクトを対応するマネージド ヒープに配置することです。オブジェクトのサイズが 85000 バイト未満の場合は SOH に配置され、それ以外の場合は LOH に配置されます。

SOHの場合、オブジェクトはガベージコレクションを実行した後、次の世代に入ります。つまり、最初にガベージ コレクションが実行されたときに、生き残ったオブジェクトが第 2 世代に入る場合、そのオブジェクトが 2 回目のガベージ コレクション後にまだガベージ コレクションされていない場合、そのオブジェクトは第 2 世代のオブジェクトになります。 object は最も古いオブジェクトであり、世代は増加しません。

ガベージ コレクションがトリガーされると、ガベージ コレクターは小さなオブジェクト ヒープをデフラグし、残っているオブジェクトをまとめて移動します。ラージ オブジェクト ヒープに関しては、メモリの移動コストが高いため、CLR チームは、メモリを使用する次のラージ オブジェクトの要求を満たすために、それらをクリアし、リサイクルされたオブジェクトのリストを作成することを選択しました。隣接するガベージ オブジェクトは A にマージされます。メモリの空きブロック。

ラージ オブジェクト ヒープは .Net 4.0 までデフラグされないことに常に注意してください。ただし、将来的にはデフラグされる可能性があります。したがって、大きなオブジェクトを割り当て、それらを移動したくない場合は、fixed ステートメントを使用できます。

次のスモール オブジェクト ヒープ SOH のリサイクル図



上の図では、最初のガベージ コレクションの前に 4 つのオブジェクト obj0 ~ 3 があり、最初のガベージ コレクションの後、obj1 と obj3 がリサイクルされます。 、同時に obj2 と obj0 が一緒に移動され、2 回目のガベージ コレクションの前に 3 つのオブジェクト obj4 ~ 6 が割り当てられ、2 回目のガベージ コレクションの後、obj2 と obj5 がリサイクルされ、obj4 と obj6 が obj0 の隣に移動されました。

下の図はラージオブジェクトヒープLOHリサイクルの概略図です



ガベージコレクションが実行される前に、最初の2番目のオブジェクトの後に合計4つのオブジェクトobj0-3があることがわかります。生成ガベージ コレクション、obj1 と obj2 がリサイクルされました。obj1 と obj2 が占有していた領域は、obj4 がメモリ割り当てを申請したときに、同時に割り当てられました。 、記憶の断片が残った。このフラグメントのサイズが 85000 バイト未満の場合、このプログラムのライフサイクル中、このフラグメントを再度使用することはできません。

適用するラージ オブジェクト領域を収容するのに十分な空きメモリがラージ オブジェクト ヒープにない場合、CLR はまずオペレーティング システムからメモリを適用しようとします。アプリケーションが失敗すると、2 番目のメモリがトリガーされます。世代をリサイクルしてメモリの一部を解放しようとします。

第 2 世代のガベージ コレクション中に、不要なメモリは VirtualFree を通じてオペレーティング システムに返すことができます。返品プロセスについては、以下の画像をご覧ください:



大きな物品はいつリサイクルされますか?

大きなオブジェクトをいつリサイクルするかを議論する前に、まず通常のガベージ コレクション操作がいつ実行されるかを見てみましょう。ガベージ コレクションは次の状況で発生します:

1. 要求されたスペースが世代 0 のメモリ サイズまたはラージ オブジェクト ヒープのしきい値を超えている場合、ほとんどのマネージド ヒープ ガベージ コレクションが発生します。

2. Collect メソッドを呼び出すとき、GC.Collect メソッドを呼び出すときに GC.MaxGeneration パラメーターが渡されると、ラージ オブジェクト ヒープのガベージ コレクションを含むすべての世代オブジェクトのガベージ コレクションが実行されます

3。システムにメモリが不足している場合、アプリケーションがメモリ不足の通知を送信したとき

4. ガベージ コレクション アルゴリズムが第 2 世代のリサイクルが有効であると判断した場合、第 2 世代のガベージ コレクションがトリガーされます

5。オブジェクト ヒープに領域サイズのしきい値プロパティがある場合、特定の世代にオブジェクトを割り当て、その世代のしきい値近くまで合計メモリ量を増やすか、この世代のヒープ サイズがヒープしきい値を超えるオブジェクトを割り当てる場合、ガベージコレクションが発生します。したがって、スモール オブジェクトまたはラージ オブジェクトを割り当てると、世代 0 ヒープまたはラージ オブジェクト ヒープのしきい値が消費されます。ガベージ コレクターがオブジェクトの世代を世代 1 または世代 2 に増やすと、世代 1 と世代 2 のしきい値が消費されます。これらのしきい値は、プログラムの実行中に動的に変化します。

ラージ オブジェクト ヒープのパフォーマンスへの影響

まず、ラージ オブジェクトを割り当てるコストを見てみましょう。 CLR が新しいオブジェクトごとにメモリを割り当てるときは、メモリがクリアされ、他のオブジェクトによって使用されないようにする必要があります (I give out はクリアされます)。これは、割り当てのコストがクリアのコストによって完全に制御されることを意味します (割り当て中にガベージ コレクションがトリガーされない限り)。 1 バイトをクリアするのに 2 サイクルかかる場合、最小の大きなオブジェクトをクリアするには 170,000 サイクルかかることになります。通常、非常に大きなオブジェクトを割り当てることはありません。たとえば、2GHz のマシンに 16M のオブジェクトを割り当てると、メモリがクリアされるまでに約 16 ミリ秒かかります。価格が高すぎます。

リサイクルにかかる費用を見てみましょう。前述したように、大きなオブジェクトは 2 世代のオブジェクトと一緒にリサイクルされます。大きなオブジェクトまたは第 2 世代のオブジェクトが占めるスペースがしきい値を超えると、第 2 世代のオブジェクトのリサイクルがトリガーされます。ラージ オブジェクト ヒープがしきい値を超えたために世代 2 のリサイクルがトリガーされた場合、世代 2 のオブジェクト ヒープ自体にはリサイクルできるオブジェクトがあまりありません。第 2 世代ヒープにオブジェクトがそれほど多くない場合、これは大きな問題ではありません。ただし、第 2 世代のヒープが大きく、多くのオブジェクトがある場合、第 2 世代の過剰なリサイクルによりパフォーマンスの問題が発生します。ラージ オブジェクトを一時的に割り当てた場合、ガベージ コレクションの実行に時間がかかります。つまり、ラージ オブジェクトを使用し続けた後、ラージ オブジェクトを解放すると、パフォーマンスに大きな悪影響が生じます。

ラージ オブジェクト ヒープ上の巨大なオブジェクトは通常、配列です (1 つのオブジェクトが非常に大きい場合がまれにあります)。オブジェクト内の要素が強参照である場合、コストは非常に高くなります。要素間に相互参照がない場合、ガベージ コレクション中に配列全体を走査する必要はありません。例: 配列を使用してバイナリ ツリーのノードを保存します。1 つの方法は、ノード内の左右のノードを強く参照することです:

class Node
{
Data d;
Node left;
Node right;
}
 
Node[] binaryTree = new Node[num_nodes];

num_nodes が大きい数である場合、各ノードは次の場所で表示する必要があることを意味します。少なくとも 2 つの参照要素。別の方法は、左右のノード要素の配列インデックス番号をノードに保存することです


class Node
{
Data d;
uint left_index;
uint right_index;
}

この場合、要素間の参照関係は binaryTree[left_index] を通じて取得できます。 。ガベージ コレクターは、ガベージ コレクションを実行するときに関連する参照要素を確認する必要がなくなりました。

ラージ オブジェクト ヒープのパフォーマンス データを収集する

ラージ オブジェクト ヒープに関連するパフォーマンス データを収集するには、いくつかの方法があります。これらの方法を説明する前に、ラージ オブジェクト ヒープに関連するパフォーマンス データを収集する必要がある理由について説明しましょう。

特定の側面でパフォーマンス データの収集を開始するとき、この側面でパフォーマンスのボトルネックの証拠がすでに見つかっているか、すべての側面を検索しても問題が見つからない可能性があります。

.Net CLR メモリ パフォーマンス カウンターは、通常、パフォーマンスの問題を探すときに最初に検討する必要があるツールです。 LOH に関連するカウンターには、第 2 世代のコレクション (第 2 世代のヒープ コレクションの数) とラージ オブジェクト ヒープ サイズが含まれます。第 2 世代のコレクションは、プロセスの開始以降に発生した第 2 世代のガベージ コレクション操作の数を示します。ラージ オブジェクト ヒープ サイズ カウンタは、空き領域を含むラージ オブジェクト ヒープの現在のサイズを示します。このカウンタは、メモリが割り当てられるたびではなく、ガベージ コレクション操作の後に更新されます。

Windows パフォーマンス カウンターで .Net CLR メモリ関連のパフォーマンス データを観察するには、以下の図を参照してください


プログラムを通じてこれらのカウンターの値をクエリすることもできます。多くの人は、パフォーマンスのボトルネックを見つけるためにプログラムを通じてパフォーマンス カウンターを収集しています。

もちろん、デバッガー Winddbg を使用してラージ オブジェクト ヒープを観察することもできます。

最後の注意: これまでのところ、ラージ オブジェクト ヒープはガベージ コレクションの一部としてデフラグされていませんが、これは clr の実装の詳細にすぎず、プログラム コードはこの機能に依存すべきではありません。オブジェクトがガベージ コレクターによって移動されないようにする場合は、fixed ステートメントを使用します。

元のアドレス: http://www.php.cn/

上記は .Net ガベージ コレクションとラージ オブジェクト処理の内容です。その他の関連コンテンツについては、PHP 中国語に注意してください。ウェブサイト (www.php.cn)!


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。