web-dev-qa-db-ja.com

.Netの非常に大きなコレクションが原因でメモリ不足の例外が発生する

.Netでコレクションがどれほど大きいかをテストしています。技術的には、コレクションオブジェクトは物理メモリのサイズまで大きくなる可能性があります。

次に、16 GBのメモリを搭載し、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)

誰もが理由を知っていますか?

32
Yin Zhu

Microsoft CLRには、64ビットバージョンであっても、最大2GBのオブジェクトサイズ制限があります。 (この制限がMonoなどの他の実装にも存在するかどうかはわかりません。)

制限は各singleオブジェクトに適用されます-すべてのオブジェクトの合計サイズではありません-つまり、いくつかの複合コレクションを使用して回避するのは比較的簡単ですソート。

ここに議論といくつかのサンプルコードがあります...

この制限について言及している公式ドキュメントはほとんどないようです。結局のところ、これは現在のCLRの実装の詳細にすぎません。私が知っている唯一の言及は このページ です:

64ビットのWindowsオペレーティングシステムで64ビットの管理対象アプリケーションを実行する場合、2ギガバイト(GB)以下のオブジェクトを作成できます。

42
LukeH

4.5より前のバージョンの.NETでは、最大オブジェクトサイズは2GBです。 4.5以降では、 gcAllowVeryLargeObjects が有効になっている場合、より大きなオブジェクトを割り当てることができます。 stringの制限は影響を受けませんが、リストは配列に基づいているため、「配列」は「リスト」もカバーする必要があります。

21
Marc Gravell

そして、明確にするために、ディクショナリは単一の配列を使用してペアを追加します。満杯になるたびに成長(倍増)します。 5億1200万個のオブジェクトがある場合、そのサイズは2Gバイトです(32ビットのオブジェクトポインターを使用し、完全な分散を想定しています)。もう1つの要素を追加すると、Dictionaryは配列サイズを再度2倍にしようとします。ブーム。

C5 HashDictionaryは線形ハッシュを使用し、おそらくそれぞれが複数(16?)の要素を含むバケットの配列を使用します。後で同じ問題が(かなり)発生するはずです。

11

「ラージオブジェクトを許可する」は、OOM例外を取り除くのに役立ちます。

非常に多くのオブジェクトを格納する必要がある場合、GCのストール(一時停止)が問題となります。私たちが行ったことは、GCからのデータの「非表示」であり、非常に実用的なソリューションになりました。

これを参照してください: https://www.infoq.com/articles/Big-Memory-Part-

辞書として機能するキャッシュを使用できます: https://github.com/aumcode/nfx/tree/master/Source/NFX/ApplicationModel/Pile

キャッシュセクションを参照してください

1
itadapter DKh