Мы используем веб-ферму с использованием .NET. Каждый веб-сервер содержит значительное количество статических объектов в своей памяти. Сбор мусора Gen 2 (GC) занимает 10-20 секунд, и он запускается каждые 5 минут. Мы столкнулись более или менее с теми же проблемами, с которыми столкнулся StackOverflow: http://samsaffron.com/archive/2011/10/28/in-managed-code-we-trust-our-recent-battles-with-the-net-garbage-collectorУведомления об утерянной коллекции мусора
В настоящий момент мы уменьшаем количество объектов в кеше. Однако это требует времени.
В то же время мы реализовали методы, документированные here, для получения уведомлений в .NET о приближении к GC. Цель состоит в том, чтобы вывести веб-сервер из фермы при приближении GC и включить его в ферму после завершения GC. Однако мы получаем уведомление только за 0,7% всех GC. Мы используем 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, вначале GC запускается, когда Gen2 достигает ~ 10 МБ. У нас много оперативной памяти, поэтому, если мы сможем установить этот порог вручную на более высокий уровень, для достижения этого порогового значения потребуется больше времени, и, по моему мнению, вероятность увеличится, чтобы получить уведомление. Есть ли способ изменить этот порог?
Это код, который регистрирует и прослушивает уведомлений:
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)
{
}
}
Не могли бы вы, возможно, разместить код, где вы регистрируетесь и слушать уведомлений GC? – Alex
'GC.RegisterForFullGCNotification (gcThreshold, gcThreshold); // Запуск потока с помощью WaitForFullGCProc. thWaitForFullGC = новая тема (WaitForFullGCProc); thWaitForFullGC.Name = "HealthTestGCNotificationListenerThread (Threshold =" + gcThreshold + ")"; thWaitForFullGC.IsBackground = true; – kopernik