Ich bin mir immer noch ziemlich unsicher. Ich arbeite seit 7 Jahren an einem Anwendungsserver. Unsere größeren Installationen verwenden 24 GB RAM. Es ist hochgradig Multithreaded und ALLE Aufrufe für GC.Collect () stießen auf wirklich schreckliche Leistungsprobleme.
Viele Komponenten von Drittanbietern verwendeten GC.Collect (), als sie es für klug hielten, dies jetzt zu tun. Eine einfache Reihe von Excel-Berichten blockierte den App Server mehrmals pro Minute für alle Threads.
Wir mussten alle Komponenten von Drittanbietern umgestalten, um die GC.Collect () -Aufrufe zu entfernen, und danach funktionierten alle einwandfrei.
Aber ich verwende Server auch unter Win32, und hier habe ich angefangen, GC.Collect () stark zu nutzen, nachdem ich eine OutOfMemoryException erhalten habe.
Aber ich bin mir auch ziemlich unsicher, weil ich oft bemerkt habe, dass es einfach funktioniert hat, wenn ich ein OOM auf 32 Bit bekomme und erneut versuche, dieselbe Operation erneut auszuführen, ohne GC.Collect () aufzurufen.
Eine Sache, die ich mich frage, ist die OOM-Ausnahme selbst ... Wenn ich das .Net Framework geschrieben hätte und keinen Speicherblock zuweisen kann, würde ich GC.Collect () verwenden, Speicher defragmentieren (??), es erneut versuchen , und wenn ich immer noch keinen freien Speicherblock finden kann, würde ich die OOM-Ausnahme auslösen.
Oder machen Sie dieses Verhalten aufgrund der Nachteile des Leistungsproblems mit GC.Collect zumindest zu einer konfigurierbaren Option.
Jetzt habe ich viel Code wie diesen in meiner App, um das Problem zu "lösen":
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);
}
(Beachten Sie, dass das Thread.Sleep () -Verhalten ein wirklich App-spezifisches Verhalten ist, da wir einen ORM-Caching-Dienst ausführen und der Dienst einige Zeit benötigt, um alle zwischengespeicherten Objekte freizugeben, wenn der RAM einige vordefinierte Werte überschreitet einige Sekunden beim ersten Mal und hat die Wartezeit bei jedem Auftreten von OOM erhöht.)