4

.NET2.0WindowsサービスアプリケーションでOutOfMemory例外のトラブルシューティングを行っています。この問題をよりよく理解するために、まず、OOM例外がスローされるまでArrayListを作成してOOM例外を生成する単純な.NETWinFormテストアプリを作成しました。例外がキャッチされてログに記録され、フォームボタンをクリックしてOOMEを再度実行できます。私が見つけた奇妙なことは、4回目の実行で、次のOOMEの前に消費されたメモリの量が約半分でした。以下にリストされている結果は、これを実行するたびに一貫しています。目を見張るようなタスクマネージャーも動作を確認します。残念ながら、より良い統計を取得しようとすると、Perfmonがフリーズしました。誰かが3回の実行後にメモリ制限が低下する理由を説明できますか?GCについての私の理解はかなり浅いです。さらに数回実行した後、GC.Collect()を実行したこともわかりますが、実行しませんでした。

更新:各arraylistアイテムにconst文字列と新しいオブジェクトを使用した場合にも大きな違いが見つかりました。コードは単純です:

const string TEST_TEXT = "xxxxxxxxxx";
ArrayList list = new ArrayList();
while (true)
{
    list.Add(TEST_TEXT);
}

ループの開始:メモリ10,350,592

  • OOM例外がスローされました
  • アレイサイズ:134,217,728

エンドループ:メモリ550,408,192

ループの開始:メモリ550,731,776

  • OOM例外がスローされました
  • アレイサイズ:134,217,728

エンドループ:メモリ551,682,048

ループの開始:メモリ551,813,120

  • OOM例外がスローされました
  • アレイサイズ:134,217,728

エンドループ:メモリ551,772,160

ループの開始:メモリ551,903,232

  • OOM例外がスローされました
  • アレイサイズ:67,108,864

エンドループ:メモリ282,869,760

ループの開始:メモリ283,004,928

  • OOM例外がスローされました
  • アレイサイズ:67,108,864

エンドループ:メモリ282,910,720

GC.Collectを手動でトリガー

ループの開始:メモリ14,245,888

  • OOM例外がスローされました
  • アレイサイズ:67,108,864

エンドループ:メモリ283,344,896

4

2 に答える 2

8

ここにいくつかのポイントがあります。これらを総合すると、質問に答えるのに十分な情報が得られることを願っています。

  • その名前にもかかわらず、OutOfMemory例外は、物理RAMと同じようにアドレス空間が不足していることを意味する可能性があります。
  • GC.Collectは、すべての未処理のRAMを収集するわけではありません。.Netのガベージコレクションは 非決定論的です。つまり、ランタイムにすべてのRAMを強制的にクリーンアップさせる方法はありません。
  • .Netのガベージコレクターは世代別です。つまり、オブジェクトがコレクションを存続すると、オブジェクトはより高い世代に移動し、収集される可能性がさらに低くなります。
  • OutOfMemory例外がスローされるまでに、配列はおそらくすでに数回の収集試行を生き延びているか、LargeObjectHeapに移動されています。
  • 配列サイズは固定されています。配列に新しい要素を追加するには、配列を完全に再割り当てする必要があります。(リストのような構造を使用すると、より良いテスト結果が得られる場合があります)。
于 2009-08-26T18:50:18.403 に答える
3

アレイを構築しているので、実行ごとに1つの大きなアレイを構築していると仮定します。この場合、ラージオブジェクトヒープに格納されます(> 85000バイトになるため)。LOHは世代別ヒープのように圧縮されていないため、表示されるサイズの減少はおそらくヒープの断片化が原因です。

于 2009-08-26T19:01:52.997 に答える