1. ホーム
  2. .net

[解決済み] なぜLarge Object Heapなのか、そしてなぜLarge Object Heapにこだわるのか?

2022-10-31 17:14:27

質問

私は世代と大きなオブジェクトヒープについて読みました。しかし、ラージオブジェクトヒープを持つことの意義(または利点)は何なのか、まだ理解できていません。

もし CLR がラージオブジェクトの保存にジェネレーション 2 に依存していたら(ジェネレーション 0 とジェネレーション 1 の閾値はラージオブジェクトを扱うには小さいと考えると)(パフォーマンスやメモリの面で)何か問題があったのでしょうか?

どのように解決するのですか?

ガベージコレクションは、参照されないオブジェクトを取り除くだけでなく コンパクトにする ヒープをコンパクトにします。 これは非常に重要な最適化です。 これは単にメモリの使用効率を上げるだけでなく (未使用の穴がない)、CPU キャッシュの効率も大幅に向上させます。 キャッシュは最近のプロセッサーでは本当に重要で、メモリ バスよりも簡単に 1 桁速くなります。

コンパクト化は、単にバイトをコピーすることで行われます。 しかし、これには時間がかかります。 オブジェクトが大きければ大きいほど、それをコピーするコストは、可能な限り CPU キャッシュ使用率を向上させるよりも高くなる可能性が高くなります。

そこで、彼らは損益分岐点を決定するために多くのベンチマークを実行しました。 そして、コピーがもはや性能を向上させないカットオフ ポイントとして、85,000 バイトに到達しました。 double 配列の特別な例外として、配列の要素が 1000 以上ある場合、「大きい」と見なされます。 ラージオブジェクトのヒープアロケータは、通常の世代アロケータが4行にアラインしてメモリを割り当てるのに対して、8行にアラインしてメモリを割り当てるという特殊な性質を持っています。このアラインはdoubleに対して大きな意味を持ち、アラインを誤ったdoubleを読み書きすると非常に高くつきます。 Microsoft のスパース情報では、奇妙なことに、long の配列について言及されていませんが、これはどうしたことでしょう。

参考までに、ラージ オブジェクト ヒープがコンパクトにならないことについて、多くのプログラマーが悩んでいます。 これは、利用可能なアドレス空間全体の半分以上を消費するプログラムを書くときに、常に引き起こされます。 次に、メモリプロファイラのようなツールを使って、未使用の仮想メモリがまだたくさんあるにもかかわらず、プログラムが爆死してしまった理由を探ります。 このようなツールは、LOHの穴、つまり、以前は大きなオブジェクトが存在していたもののガベージコレクションされてしまった未使用のメモリチャンクを示します。 LOHの穴は、同じサイズかそれより小さいオブジェクトの割り当てによってのみ再利用できるのです。 本当の問題は、プログラムが以下のものを消費することが許されると仮定することです。 すべて を消費することが許されると仮定することです。

そうでなければ、64 ビットのオペレーティング システム上でコードを実行するだけで完全に消えてしまうような問題。 64 ビットのプロセスには 8 テラバイト であり、32 ビット プロセスよりも 3 桁多く利用可能です。 これは、32 ビット プロセスよりも 3 桁多い数字です。

長い話を端折ると、LOH はコードをより効率的に実行させます。 その代償として、利用可能な仮想メモリ アドレス空間はより効率的に使用されません。


UPDATE, .NET 4.5.1 は LOH のコンパクト化をサポートするようになりました。 GCSettings.LargeObjectHeapCompactionMode というプロパティが追加されました。 結果に注意してください。