Generations と Large object heap について読みました。しかし、大きなオブジェクト ヒープを持つことの重要性 (または利点) をまだ理解できていません。
大きなオブジェクトを格納するために CLR が第 2 世代 (大きなオブジェクトを処理するには Gen0 と Gen1 のしきい値が小さいことを考慮すると) に依存していた場合、(パフォーマンスまたはメモリの点で) 何が問題になる可能性がありますか?
Generations と Large object heap について読みました。しかし、大きなオブジェクト ヒープを持つことの重要性 (または利点) をまだ理解できていません。
大きなオブジェクトを格納するために CLR が第 2 世代 (大きなオブジェクトを処理するには Gen0 と Gen1 のしきい値が小さいことを考慮すると) に依存していた場合、(パフォーマンスまたはメモリの点で) 何が問題になる可能性がありますか?
ガベージ コレクションは、参照されていないオブジェクトを取り除くだけでなく、ヒープを圧縮します。これは非常に重要な最適化です。メモリの使用がより効率的になる (未使用のホールがなくなる) だけでなく、CPU キャッシュがより効率的になります。キャッシュは、最新のプロセッサでは非常に重要であり、メモリ バスよりも桁違いに高速です。
圧縮は、単純にバイトをコピーすることによって行われます。ただし、それには時間がかかります。オブジェクトが大きいほど、それをコピーするコストが CPU キャッシュ使用率の改善を上回る可能性が高くなります。
そこで彼らは、損益分岐点を決定するために一連のベンチマークを実行しました。そして、コピーがもはやパフォーマンスを向上させないカットオフポイントとして 85,000 バイトに到達しました。double の配列の特別な例外を除いて、配列に 1000 を超える要素がある場合、それらは「大きい」と見なされます。これは 32 ビット コードのもう 1 つの最適化です。ラージ オブジェクト ヒープ アロケーターには、4 にのみ整列された通常の世代別アロケーターとは異なり、8 に整列されたアドレスにメモリを割り当てるという特別なプロパティがあります。 、アラインされていない double の読み取りまたは書き込みは非常にコストがかかります。奇妙なことに、まばらなマイクロソフトの情報では、長い配列について言及されていません。それがどうなっているのかわかりません。
大きなオブジェクト ヒープが圧縮されないことについて、多くのプログラマーが不安を感じています。これは、使用可能なアドレス空間全体の半分以上を消費するプログラムを作成したときに必ず発生します。続いて、メモリ プロファイラーのようなツールを使用して、使用可能な未使用の仮想メモリがまだたくさんあるにもかかわらず、プログラムが爆撃した理由を調べました。このようなツールは、以前は大きなオブジェクトが存在していたが、ガベージ コレクションが行われた未使用のメモリ チャンクである LOH の穴を示します。これは LOH の避けられない代償であり、ホールはサイズが等しいかそれより小さいオブジェクトの割り当てによってのみ再利用できます。本当の問題は、プログラムがいつでもすべての仮想メモリを消費できるようにする必要があると仮定することです。
64 ビット オペレーティング システムでコードを実行するだけで完全に解消される問題。64 ビット プロセスでは、32 ビット プロセスよりも 3 桁多く、8 テラバイトの仮想メモリ アドレス空間が利用可能です。穴を使い果たすことはできません。
簡単に言うと、LOH によってコードの実行がより効率的になります。使用可能な仮想メモリ アドレス空間の使用効率が低下します。
更新、.NET 4.5.1 は、LOH、GCSettings.LargeObjectHeapCompactionModeプロパティの圧縮をサポートするようになりました。結果に注意してください。
オブジェクトのサイズが固定された値(.NET 1では85000バイト)より大きい場合、CLRはそれをラージオブジェクトヒープに配置します。これは最適化します:
この記事が示すように、スモール オブジェクト ヒープ (SOH) とラージ オブジェクト ヒープ (LOH) の本質的な違いは、SOH のメモリは収集時に圧縮されますが、LOH は圧縮されないことです。大きなオブジェクトの圧縮には多くのコストがかかります。この記事の例と同様に、メモリ内の 1 バイトを移動するには 2 サイクルが必要であり、2 GHz のコンピューターで 8 MB のオブジェクトを圧縮するには 8 ミリ秒が必要であり、これは大きなコストです。大きなオブジェクト (ほとんどの場合は配列) が実際には非常に一般的であることを考えると、Microsoft が大きなオブジェクトをメモリに固定して LOH を提案するのはそのためだと思います。
ところで、この投稿によると、LOH は通常、メモリ フラグメントの問題を生成しません。
原則として、プロセスが短期間の大きなオブジェクトを大量に作成する可能性は低く(おそらく設計が悪い)、CLRは大きなオブジェクトを別のヒープに割り当て、通常のヒープとは異なるスケジュールでGCを実行します。http://msdn.microsoft.com/en-us/magazine/cc534993.aspx
私はCLRの専門家ではありませんが、大きなオブジェクト専用のヒープを用意することで、既存の世代のヒープの不要なGCスイープを防ぐことができると思います。大きなオブジェクトを割り当てるには、大量の連続した空きメモリが必要です。世代別ヒープに散在する「穴」からそれを提供するには、頻繁な圧縮が必要になります(これはGCサイクルでのみ実行されます)。