.NET を使用して Web ファームを実行しています。各 Web サーバーは、そのメモリ内にかなりの量の静的オブジェクトを保持しています。Gen 2 ガベージ コレクション (GC) には 10 ~ 20 秒かかり、5 分ごとに実行されます。StackOverflow が遭遇したのとほぼ同じ問題に遭遇しました: http://samsaffron.com/archive/2011/10/28/in-managed-code-we-trust-our-recent-battles-with-the-ネットガベージコレクター
現在、キャッシュ内のオブジェクトの数を減らしています。ただし、これには時間がかかります。
同時に、GC の接近について .NET で通知を受け取るために、ここに記載されているメソッドを実装しました。目標は、GC が近づいているときに Web サーバーをファームから取り出し、GC が終了した後にファームに含めることです。ただし、すべての GC の 0.7% についてのみ通知を受け取ります。maxGenerationThreshold と largeObjectHeapThreshold を 8 に設定しています。他のしきい値も試しましたが、失敗した GC の量は変わりませんでした。
同時サーバー ガベージ コレクションを使用しています ( http://msdn.microsoft.com/en-us/library/ms229357.aspx )。GCLatencyMode はインタラクティブです ( http://msdn.microsoft.com/en-us/library/system.runtime.gclatencymode.aspxを参照)。ここでも、他の GC モード (ワークステーション モード、バッチなど) を使用しようとしました。また、ほとんどの GC について通知を受け取りませんでした。
何か問題があるのでしょうか、それとも GC が発生するたびに通知を受け取ることができないのでしょうか? 通知の数を増やすにはどうすればよいですか?
http://assets.red-gate.com/community/books/assets/Under_the_Hood_of_.NET_Management.pdfによると、最初に Gen2 が ~10 MB に達すると GC がトリガーされます。大量の RAM があるため、このしきい値を手動でより高いレベルに設定できれば、このしきい値に到達するまでにより多くの時間がかかり、私の理解では、通知を受け取る確率が高くなります。このしきい値を変更する方法はありますか?
これは、通知を登録してリッスンするコードです。
GC.RegisterForFullGCNotification(gcThreshold, gcThreshold);
// Start a thread using WaitForFullGCProc.
thWaitForFullGC = new Thread(WaitForFullGCProc);
thWaitForFullGC.Name = "HealthTestGCNotificationListenerThread (Threshold=" + gcThreshold + ")";
thWaitForFullGC.IsBackground = true;
WaitForFullGCProc():
private void WaitForFullGCProc()
{
try
{
while (!gcAbort)
{
// Check for a notification of an approaching collection.
GCNotificationStatus s;
do
{
int timeOut = CheckForMissedGc() > 0 ? 5000 : (10 * 60 * 1000);
s = GC.WaitForFullGCApproach(timeOut);
if (this.GcState == GCState.InducedUnnotified)
{
// Set the GcState back to okay to prevent the message from staying in the ApplicationMonitoring.
this.GcState = GCState.Okay;
}
} while (s == GCNotificationStatus.Timeout);
if (s == GCNotificationStatus.Succeeded)
{
SetGcState(GCState.Approaching, "GC is approaching..");
gcApproachNotificationCount++;
}
else
{
...
}
Stopwatch stopwatch = Stopwatch.StartNew();
s = GC.WaitForFullGCComplete((int)PrewarnTime.TotalMilliseconds);
long elapsed = stopwatch.ElapsedMilliseconds;
if (s == GCNotificationStatus.Timeout)
{
if (this.ForceGCWhenApproaching && !this.IsInGc && !this.IsPeriodicGcApproaching)
{
this.IsInGc = true;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true);
GC.WaitForPendingFinalizers();
elapsed = stopwatch.ElapsedMilliseconds;
this.IsInGc = false;
}
}
}
gcAbort = false;
}
catch (Exception e)
{
}
}