Todavía estoy bastante inseguro sobre esto. Estoy trabajando desde hace 7 años en un servidor de aplicaciones. Nuestras instalaciones más grandes utilizan 24 GB de RAM. Es altamente multiproceso, y TODAS las llamadas para GC.Collect () se encontraron con problemas de rendimiento realmente terribles.
Muchos componentes de terceros usaron GC.Collect () cuando pensaron que era inteligente hacer esto ahora. Entonces, un simple grupo de informes de Excel bloqueó el servidor de aplicaciones para todos los hilos varias veces por minuto.
Tuvimos que refactorizar todos los componentes de terceros para eliminar las llamadas GC.Collect (), y todo funcionó bien después de hacer esto.
Pero también estoy ejecutando servidores en Win32, y aquí comencé a usar GC.Collect () después de obtener una excepción OutOfMemoryException.
Pero también estoy bastante inseguro sobre esto, porque a menudo me di cuenta, cuando obtengo un OOM en 32 Bit, y vuelvo a intentar ejecutar la misma Operación nuevamente, sin llamar a GC.Collect (), simplemente funcionó bien.
Una cosa que me pregunto es la Excepción OOM en sí ... Si hubiera escrito .Net Framework, y no puedo asignar un bloque de memoria, usaría GC.Collect (), defrag memory (??), intente nuevamente , y si todavía no puedo encontrar un bloque de memoria libre, entonces lanzaría la OOM-Exception.
O al menos haga que este comportamiento sea una opción configurable, debido a los inconvenientes del problema de rendimiento con GC.Collect.
Ahora tengo un montón de código como este en mi aplicación para "resolver" el problema:
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);
}
(Tenga en cuenta que el comportamiento Thread.Sleep () es un comportamiento realmente específico de la aplicación, porque estamos ejecutando un servicio de almacenamiento en caché ORM, y el servicio tarda un tiempo en liberar todos los objetos en caché, si la RAM excede algunos valores predefinidos. unos segundos la primera vez, y ha aumentado el tiempo de espera cada vez que aparece OOM).