なぜ大きなオブジェクトヒープであり、なぜ私たちは気にするのですか?


105

ジェネレーションとラージオブジェクトヒープについて読みました。しかし、私はまだ大きなオブジェクトヒープを持つことの重要性(または利点)が何であるか理解できませんか?

ラージオブジェクトを格納するためにCLRがジェネレーション2(Gen0およびGen1のしきい値が小さいことを考慮すると)に依存している場合、(パフォーマンスまたはメモリの観点から)何が問題になっている可能性がありますか?


6
これにより、.NETデザイナに2つの質問が生じます。1. OutOfMemoryExceptionがスローされる前にLOHデフラグが呼び出されないのはなぜですか?2. LOHオブジェクトが一緒に滞在するための親和性を持たないのはなぜですか(大きなものがヒープの終わりを優先し、最初は小さい)
Jacob Brewer

回答:


195

ガベージコレクションは、参照されていないオブジェクトを削除するだけでなく、ヒープも圧縮します。これは非常に重要な最適化です。メモリの使用効率を上げるだけでなく(未使用のホールをなくす)、CPUキャッシュをより効率的にします。キャッシュは最近のプロセッサでは非常に重要であり、メモリバスよりもはるかに高速です。

バイトをコピーするだけで圧縮が行われます。ただし、これには時間がかかります。オブジェクトが大きいほど、オブジェクトをコピーするコストがCPUキャッシュ使用率の改善の可能性を上回る可能性が高くなります。

そこで、彼らは損益分岐点を決定するために一連のベンチマークを実行しました。そして、コピーがパフォーマンスを改善しないカットオフポイントとして85,000バイトに到達しました。doubleの配列の特別な例外を除いて、配列に1000を超える要素がある場合、それらは「大きい」と見なされます。これは32ビットコードの別の最適化です。ラージオブジェクトヒープアロケーターには、8にアライメントされたアドレスにメモリを割り当てるという特別なプロパティがあります。これは、4にのみアライメントを割り当てる通常の世代別アロケーターとは異なり、そのアライメントはdoubleの大きな問題です、誤って配置されたdoubleの読み取りまたは書き込みは非常に高価です。奇妙なことに、まばらなMicrosoftの情報では、長い配列については言及されていません。

Fwiw、ラージオブジェクトヒープが圧縮されないことに多くのプログラマーが悩んでいます。これは、利用可能なアドレス空間全体の半分以上を消費するプログラムを書いたときに必ず発生します。続いて、メモリプロファイラーのようなツールを使用して、未使用の仮想メモリがまだたくさん残っているにもかかわらず、プログラムが攻撃された理由を調べました。このようなツールは、LOHの穴、以前は大きなオブジェクトが存在していたがガベージコレクションされていた未使用のメモリチャンクを示します。これはLOHの必然的な価格です。この穴は、サイズが同じか小さいオブジェクトの割り当てによってのみ再利用できます。実際の問題は、プログラムがいつでもすべての仮想メモリを消費できるようにする必要があることを想定しています。

64ビットオペレーティングシステムでコードを実行するだけで完全に解消される問題。64ビットプロセスには、8テラバイトの仮想メモリアドレス空間があり、32ビットプロセスより3桁大きくなります。あなただけの穴を使い果たすことはできません。

要するに、LOHはコードの実行をより効率的にします。使用可能な仮想メモリアドレス空間を使用すると、効率が低下します。


UPDATE、.NET 4.5.1はLOH、GCSettings.LargeObjectHeapCompactionModeプロパティの圧縮をサポートするようになりました。結果に注意してください。


3
@Hans Passant、x64システムについて明確にしていただけませんか?この問題は完全に消えますか?
Johnny_D、2012年

LOHのいくつかの実装の詳細は理にかなっていますが、いくつかは私を困惑させます。例えば、私は多くの大規模なオブジェクトが作成され、放棄されている場合、一般的にそれらを削除することが望ましい場合があることを理解することができ一斉 Gen0のコレクションに断片的なよりも、Gen2のコレクションでは、しかし、1つは作成し、破棄がこれに22,000文字列の配列を例えば場合外部参照が存在しない場合、Gen0およびGen1コレクションが配列への参照が存在するかどうかに関係なく、すべての22,000文字列を「ライブ」としてタグ付けすることにはどのような利点がありますか?
スーパーキャット2012年

6
もちろん、断片化の問題はx64でもまったく同じです。それだけでより多くのことがでキックする前に、サーバー・プロセスを実行するのに数日かかります。
ローター

1
うーん、いや、決して3桁も過小評価しないでください。4テラバイトのヒープのガベージコレクションにかかる時間は、それに近づくずっと前に発見することを避けられないものです。
ハンスパッサント2015

2
@HansPassantこのステートメントについて詳しく説明してください:「4テラバイトのヒープのガベージコレクションにかかる時間は、それに近づくずっと前に発見することを避けられないものです。」
比較的

9

オブジェクトのサイズが固定値(.NET 1では85000バイト)より大きい場合、CLRはそれをラージオブジェクトヒープに配置します。これは最適化します:

  1. オブジェクトの割り当て(小さなオブジェクトは大きなオブジェクトと混合されません)
  2. ガベージコレクション(LOHはフルGCでのみ収集)
  3. メモリのデフラグ(LOHがされて決して稀に圧縮していません)

9

小さいオブジェクトヒープ(SOH)と大きいオブジェクトヒープ(LOH)の本質的な違いは、この記事で説明されているように、LOHは収集されないが、SOHのメモリは収集時に圧縮されることです。大きなオブジェクトを圧縮すると、コストがかかります。記事の例と同様に、メモリ内の1バイトの移動には2サイクルが必要であり、2GHzコンピュータで8MBオブジェクトを圧縮するには8msが必要であり、これは大きなコストです。ラージオブジェクト(ほとんどの場合は配列)は実際には非常に一般的であると考えると、Microsoftがラージオブジェクトをメモリに固定してLOHを提案するのはそのためだと思います。

ところで、この投稿によると、LOHは通常、メモリフラグメントの問題を生成しません。


1
管理対象オブジェクトに大量のデータをロードすると、通常、LOHを圧縮するための8ミリ秒のコストが削減されます。実際には、ほとんどのビッグデータアプリケーションでは、LOHのコストは他のアプリケーションパフォーマンスに比べてわずかです。
Shiv 2016

3

プリンシパルは、プロセスが多数の短命のラージオブジェクトを作成する可能性が低い(そしておそらく非常に悪い設計)であるため、CLRはラージオブジェクトを別のヒープに割り当て、その上で通常のヒープとは異なるスケジュールでGCを実行します。http://msdn.microsoft.com/en-us/magazine/cc534993.aspx


また、たとえば少量のメモリが解放され、巨大なオブジェクトを新しい場所にコピーする必要がある場合は特に、メモリを圧縮するのに長い時間がかかるため、ジェネレーション2に大きなオブジェクトを配置すると、パフォーマンスが低下する可能性があります。現在のLOHは、パフォーマンス上の理由から圧縮されていません。
クリストファーカレンズ2012年

GCがうまく処理できないので、これは悪い設計だと思います。
CodesInChaos 2012年

@CodeInChaosどうやら、.NET 4.5
Christian.K

1
@CodeInChaos:システムがgen2コレクションまで待機してから、存続期間の短いLOHオブジェクトからもメモリを再利用しようとするのは理にかなっているかもしれませんが、LOHオブジェクト(およびそれらが保持するオブジェクト)を宣言することによるパフォーマンス上の利点はわかりません参照)gen0とgen1のコレクションの間、無条件にライブします。そのような仮定によって可能になるいくつかの最適化はありますか?
スーパーキャット2012

@supercat Myles McDonnellが言及したリンクを見た。私の理解は次のとおりです。1. LOH収集は第2世代GCで行われます。2. LOHコレクションには圧縮が含まれていません(記事が作成された時点では)。代わりに、死んだオブジェクトを再利用可能としてマークし、十分な大きさの場合、これらのホールは将来のLOH割り当てに役立ちます。ポイント1のため、gen 2に多くのオブジェクトがある場合、gen 2 GCは遅くなることを考えると、この場合はLOHをできるだけ使用しない方が良いと思います。
ロビーファン

0

私はCLRの専門家ではありませんが、大きなオブジェクト専用のヒープがあると、既存の世代ヒープの不要なGCスイープを防ぐことができると思います。大きなオブジェクトを割り当てるには、大量の連続した空きメモリが必要です。世代ヒープに散在する「穴」からそれを提供するには、頻繁な圧縮が必要です(GCサイクルでのみ実行されます)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.