12

16 GB の RAM を搭載した Windows Server 2008 x64 で .NET アプリケーションを実行しています。このアプリケーションは、非常に大量のデータ (約 64 GB) をフェッチして分析し、一度にすべてのデータをメモリに保持する必要があります。

予想されること: プロセス サイズが 16GB を超えて 64GB に拡大します。Windows は仮想メモリを使用して、必要に応じてディスクとの間で余分なデータをページングします。これは、従来の仮想メモリの使用例です。

私が実際に見たもの:プロセスサイズは物理メモリの量(16GB)に制限されています。アプリケーションは、その時間の 99.8% をガベージ コレクターで費やします。

アプリケーションが仮想メモリを使用できないのはなぜですか? これは、.NET ガベージ コレクターの構成の問題ですか、それとも Windows x64 仮想メモリ マネージャー自体の問題ですか? アプリケーションが物理メモリに制限されるのではなく、仮想メモリを使用するようにするにはどうすればよいですか?

ありがとう。

-- ブライアン

更新: 同じ動作を示す非常に小さなプログラムを作成しました。

using System;

namespace GCTest
{
    class Program
    {
        static void Main()
        {
            byte[][] arrays = new byte[100000000][];
            for (int i = 0; i < arrays.Length; ++i)
            {
                arrays[i] = new byte[320];
                if (i % 100000 == 0)
                {
                    Console.WriteLine("{0} arrays allocated", i);
                    System.Threading.Thread.Sleep(100);
                }
            }
        }
    }
}

試してみたい場合は、必ず x64 用にビルドしてください。システムに負荷をかけるために、定数を少し変更する必要がある場合があります。私が見た動作は、サイズが 16GB に近づくとプロセスが停止することです。エラー メッセージや例外はスローされません。パフォーマンス モニターは、GC の CPU 時間の割合が 100% に近づいていることを報告します。

これは受け入れられませんか?仮想記憶システムはどこにありますか?

4

2 に答える 2

10

ページング ファイルがそのサイズに拡張できるように構成されていることを確認しましたか?

アップデート

私はあなたの与えられた例でこれをかなりいじっていましたが、ここに私が見ているものがあります。

システム: Windows 7 64 ビット、6 GB のトリプルチャネル RAM、8 コア。

  1. OS の別のスピンドルに追加のページング ファイルが必要です。そうしないと、この種の調査によってマシンが故障してしまいます。すべてが同じページング ファイルをめぐって争っている場合、事態はさらに悪化します。

  2. 大量のデータが GC で世代から世代へとプロモートされているのに加えて、多数の GC スイープ/コレクション、および物理メモリの制限に達した結果として大量のページ フォールトが発生しています。物理メモリが非常に多く使い果たされると、世代のスイープと昇格がトリガーされ、ページアウトされた大量のメモリがタッチされ、タッチされたメモリがページインされ、他のメモリがページインされるため、デス スパイラルが発生すると想定することしかできません。追い出されます。全体がねっとりした混乱で終わります。これは、最終的にスモール オブジェクト ヒープになる、存続期間の長いオブジェクトを多数割り当てる場合には避けられないようです。

これを、ある方法でオブジェクトを割り当てると、それらを大きなオブジェクト ヒープに直接割り当てることと比較してください (同じスイープや昇格の問題は発生しません)。

private static void Main()
{
    const int MaxNodeCount = 100000000;
    const int LargeObjectSize = (85 * 1000);

    LinkedList<byte[]> list = new LinkedList<byte[]>();

    for (long i = 0; i < MaxNodeCount; ++i)
    {
        list.AddLast(new byte[LargeObjectSize]);

        if (i % 100000 == 0)
        {
            Console.WriteLine("{0:N0} 'approx' extra bytes allocated.",
               ((i + 1) * LargeObjectSize));
        }
    }
}

これは期待どおりに機能します。つまり、仮想メモリが使用され、最終的に使い果たされます - 私の環境\構成では54GBです。

そのため、寿命の長い小さなオブジェクトを大量に割り当てると、物理メモリが使い果たされたときに世代のスイープと昇格が行われるため、最終的に GC で悪循環につながるようです。これはページ ファイルの死のスパイラルです。

更新 2

問題を調査している間、私は多くのオプション\構成で遊んでいましたが、大きな違いはありませんでした:

  • サーバー GC モードを強制します。
  • 低レイテンシ GC の構成。
  • GC に GC の償却を強制するさまざまな組み合わせ。
  • Min\Max プロセス ワーキング セット。
于 2010-06-22T14:57:48.813 に答える
2

大きなデータへの参照を保持していないようです。ガベージ コレクターは、参照されたオブジェクトを収集しません。

于 2010-06-22T14:50:36.343 に答える