Prowadzimy farmę internetową przy użyciu .NET. Każdy serwer WWW zawiera znaczną ilość statycznych obiektów w swojej pamięci. Odśmiecanie Gen 2 (GC) trwa 10-20 sekund i trwa co 5 minut. Przeszliśmy mniej więcej w tych samych problemach, które napotkał StackOverflow: http://samsaffron.com/archive/2011/10/28/in-managed-code-we-trust-our-recent-battles-with-the-net-garbage-collectorNieodebrane powiadomienia o zbiorze śmieci
W tej chwili zmniejszamy liczbę obiektów w pamięci podręcznej. Jednak wymaga to czasu.
W tym samym czasie wdrożyliśmy metody udokumentowane jako here, aby otrzymywać powiadomienia w .NET o zbliżaniu się do GC. Celem jest wyjęcie serwera z farmy, gdy zbliża się GC i włączenie go do farmy po zakończeniu GC. Otrzymujemy jednak tylko powiadomienie o 0,7% wszystkich GC. Używamy maxGenerationThreshold i largeObjectHeapThreshold z 8. Próbowaliśmy innych progów, ale ilość nieodebranych GC nie uległa zmianie.
Używamy zbierania śmieci z serwera współbieżnego (http://msdn.microsoft.com/en-us/library/ms229357.aspx). GCLatencyMode jest interaktywny (patrz http://msdn.microsoft.com/en-us/library/system.runtime.gclatencymode.aspx). Ponownie spróbowaliśmy użyć innych trybów GC (tryb stacji roboczej, wsad itd.). I znowu nie otrzymaliśmy powiadomienia dla większości GC.
Czy robimy coś złego, czy też niemożliwe jest otrzymanie powiadomienia o każdym GC, który ma miejsce? Jak zwiększyć liczbę powiadomień?
Zgodnie z http://assets.red-gate.com/community/books/assets/Under_the_Hood_of_.NET_Management.pdf, na początku wywoływane jest GC, gdy Gen2 trafi ~ 10 MB. Mamy dużo pamięci RAM, więc jeśli moglibyśmy ustawić ten próg ręcznie na wyższy poziom, osiągnięcie tego progu zajęłoby więcej czasu iw moim rozumieniu prawdopodobieństwo wzrosłoby, aby otrzymać powiadomienie. Czy istnieje sposób na modyfikację tego progu?
Jest to kod, który rejestruje i słucha zgłoszeń:
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)
{
}
}
prawdopodobnie można pisać kod, gdzie się zarejestrować i słuchać powiadomień GC? – Alex
'GC.RegisterForFullGCNotification (gcThreshold, gcThreshold); // Rozpocznij wątek za pomocą WaitForFullGCProc. thWaitForFullGC = new Thread (WaitForFullGCProc); thWaitForFullGC.Name = "HealthTestGCNotificationListenerThread (Threshold =" + gcThreshold + ")"; thWaitForFullGC.IsBackground = true; – kopernik