.NETの非常に大きなコレクションは、メモリの例外を引き起こします
-
01-10-2019 - |
質問
私は、.NETでコレクションがどれほど大きくなるかをテストしています。技術的には、収集オブジェクトは物理メモリのサイズに成長する可能性があります。
次に、16GBのメモリを備えたSeverで次のコードをテストし、Windows 2003サーバーとVisual Studio 2008を実行しています。F#とC#コードの両方をテストし、実行中にタスクマネージャーを調べました。 2GBのメモリを拡大した後、プログラムはメモリ外の例外でクラッシュしたことがわかります。プロパティページのターゲットプラットフォームをX64に設定しました。
open System.Collections.Generic
let d = new Dictionary<int, int>()
for i=1 to 1000000000 do
d.Add(i,i)
私は同じテストをしました C5 コレクションライブラリ。その結果、C5の辞書はメモリ全体を使い果たすことができます。コードはC5を使用します。
let d = C5.HashDictionary<int, int> ()
for i=1 to 1000000000 do
d.Add(i,i)
誰かが理由を知っていますか?
解決
Microsoft CLRには、64ビットバージョンでさえ2GBの最大オブジェクトサイズ制限があります。 (この制限がモノなどの他の実装にも存在するかどうかはわかりません。)
制限はそれぞれに適用されます 独身 オブジェクト - すべてのオブジェクトの合計サイズではありません - つまり、何らかの複合コレクションを使用して回避するのは比較的簡単です。
ここには議論といくつかの例のコードがあります...
この制限を指す公式の文書はほとんどないようです。結局のところ、それは現在のCLRの実装の詳細です。私が知っている唯一の言及はです このページで:
64ビットWindowsオペレーティングシステムで64ビットマネージドアプリケーションを実行すると、2ギガバイト(GB)以下のオブジェクトを作成できます。
他のヒント
4.5より前の.NETのバージョンでは、最大オブジェクトサイズは2GBです。 4.5以降から、より大きなオブジェクトを割り当てることができます gcallowverylargeObjects 有効になっています。の制限に注意してください string
影響は影響されませんが、リストはアレイによってバックされるため、「配列」も「リスト」をカバーする必要があります。
明確にするために、辞書は単一の配列を使用してペアを追加します。それは栽培されています(2倍になりましたか?)満杯になるたびに。 5億1,200万個のオブジェクトがある場合、そのサイズは2GByte(32ビットオブジェクトポインターを備えており、完全な分布を想定しています)。もう1つの要素を追加すると、辞書はアレイサイズを再度2倍にしようとします。ブーム。
C5 Hashdictionaryは線形ハッシュを使用し、おそらく複数の(16?)要素を含むバケットの配列を使用します。後で同じ問題に遭遇するはずです。
「大きなオブジェクトを許可する」は、OOM例外を取り除くのに役立ちます。
非常に多くのオブジェクトを保存する必要がある場合、表示される問題はGCストール(一時停止)です。私たちがやったことは、GCからのデータの「隠れ」であり、非常に実用的なソリューションに変わりました。
これを参照してください: https://www.infoq.com/articles/big-memory-part-3
辞書として機能するキャッシュを使用できます。https://github.com/aumcode/nfx/tree/master/source/nfx/applicationmodel/pile
キャッシュセクションを参照してください