私はまだこれについてかなり確信が持てません。私は7年間、アプリケーションサーバーに取り組んでいます。より大きなインストールでは、24 GBのRAMを使用します。その非常にマルチスレッド化された、GC.Collect()のすべての呼び出しは、本当にひどいパフォーマンスの問題に遭遇しました。
多くのサードパーティコンポーネントは、GC.Collect()を使用して、現時点でこれを行うのが賢明だと考えました。そのため、Excelレポートの単純な束が、1分間に数回すべてのスレッドのアプリケーションサーバーをブロックしました。
GC.Collect()呼び出しを削除するために、すべてのサードパーティコンポーネントをリファクタリングする必要があり、これを実行した後はすべて正常に動作しました。
しかし、Win32でもサーバーを実行しています。OutOfMemoryExceptionを取得した後、GC.Collect()を頻繁に使用し始めました。
しかし、私もこれにかなり確信が持てません。32ビットでOOMを取得し、GC.Collect()を呼び出さずに同じ操作を再度実行しようとすると、うまく機能したためです。
私が不思議に思うのは、OOM例外自体です... .Net Frameworkを作成していて、メモリブロックを割り当てることができない場合、GC.Collect()を使用してメモリをデフラグ(??)し、再試行します。 、まだ空きメモリブロックが見つからない場合は、OOM例外をスローします。
または、GC.Collectのパフォーマンス問題の欠点のため、少なくともこの動作を構成可能なオプションとして設定します。
今私は私の問題を「解決する」ためにこのようなコードをたくさん持っています:
public static TResult ExecuteOOMAware<T1, T2, TResult>(Func<T1,T2 ,TResult> func, T1 a1, T2 a2)
{
int oomCounter = 0;
int maxOOMRetries = 10;
do
{
try
{
return func(a1, a2);
}
catch (OutOfMemoryException)
{
oomCounter++;
if (maxOOMRetries > 10)
{
throw;
}
else
{
Log.Info("OutOfMemory-Exception caught, Trying to fix. Counter: " + oomCounter.ToString());
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(oomCounter * 10));
GC.Collect();
}
}
} while (oomCounter < maxOOMRetries);
// never gets hitted.
return default(TResult);
}
(ORMキャッシュサービスを実行しているため、Thread.Sleep()の動作は実際にはアプリ固有の動作であり、RAMが事前定義された値を超えた場合、サービスはキャッシュされたすべてのオブジェクトを解放するのにしばらく時間がかかります。初回は数秒、OOMが発生するたびに待機時間が長くなります。)