web-dev-qa-db-ja.com

短期間の.NETガベージコレクションの防止

非常に大量のデータを処理する高性能アプリケーションがあります。非常に短期間で膨大な量の情報を受信、分析、破棄しています。これにより、現在最適化しようとしている大量のオブジェクトチャーンが発生しますが、二次的な問題も発生します。ガベージコレクションが起動すると、クリーンアップ中に長い遅延が発生する可能性があります(長いとは、10〜100ミリ秒を意味します)。これは許容できる時間の99%ですが、約1〜2分間の短い時間枠では、ガベージコレクションが遅延を引き起こさないことを絶対に確認する必要があります。これらの期間がいつ発生するかは事前に知っており、この期間中にガベージコレクションが行われないようにする方法が必要なだけです。アプリケーションは.NET 4.0 Frameworkを使用してC#で記述されており、それが重要な場合はマネージコードとアンマネージコードの両方を使用します。

私の質問は;

  1. プログラム全体でガベージコレクションを一時停止することは可能ですか?
  2. System.GC.Collect()を使用して、ガベージコレクションを解放する必要があるウィンドウの前にガベージコレクションを強制することは可能ですか?
  3. ガベージコレクション全体の必要性を最小限に抑えるために、どのようなアドバイスがありますか?

注-このシステムは非常に複雑で、多くの異なるコンポーネントがあります。私は、プログラムのすべてのクラスにカスタムIDisposableインターフェイスを実装する必要があるアプローチを避けたいと考えています。

60
drobertson

.NET 4.6は2つの新しいメソッドを追加しました: GC.TryStartNoGCRegion および GC.EndNoGCRegion これだけ。

79
xanatos
_GCLatencyMode oldMode = GCSettings.LatencyMode;

// Make sure we can always go to the catch block, 
// so we can set the latency mode back to `oldMode`
RuntimeHelpers.PrepareConstrainedRegions();

try
{
    GCSettings.LatencyMode = GCLatencyMode.LowLatency;

    // Generation 2 garbage collection is now
    // deferred, except in extremely low-memory situations
}
finally
{
    // ALWAYS set the latency mode back
    GCSettings.LatencyMode = oldMode;
}
_

これにより、できる限りGCを無効にできます。次の状態になるまで、オブジェクトの大きなコレクションは実行されません。

  • GC.Collect()を呼び出します
  • _GCSettings.LatencyMode_をLowLatency以外に設定した
  • OSはメモリ不足の信号をCLRに送信します

tryブロックにいる間、メモリ使用量は非常に速く上昇する可能性があるため、これを行うときは注意してください。 GCが収集している場合は、何らかの理由で収集しています。システムに大量のメモリがある場合にのみ、真剣に考慮する必要があります。

質問3を参照すると、ファイルシステムI/Oまたはネットワーク経由で情報を受信して​​いる場合、バイト配列などのオブジェクトを再利用できますか?その情報をカスタムクラスに解析している場合は、それらも再利用してみてください。しかし、正確に何をしているかを知らなければ、あまり良いアドバイスをすることはできません。

以下も役立つMSDNの記事です。

注:_GCSettings.LatencyMode = GCLatencyMode.LowLatency_は、_GCSettings.IsServerGC == false_の場合にのみ設定できます。 IsServerGCは_App.config_で変更できます:

_  <runtime>
    <gcServer enabled="false" />
  </runtime>
_
75
user153498