La mejor práctica es no forzar la recolección de basura.
Según MSDN:
"Es posible forzar la recolección de basura llamando a Collect, pero la mayoría de las veces, esto debe evitarse porque puede crear problemas de rendimiento".
Sin embargo, si puede probar su código de manera confiable para confirmar que llamar a Collect () no tendrá un impacto negativo, continúe ...
Solo trate de asegurarse de que los objetos estén limpios cuando ya no los necesite. Si tiene objetos personalizados, observe el uso de la "declaración de uso" y la interfaz IDisposable.
Este enlace tiene algunos buenos consejos prácticos con respecto a la liberación de memoria / recolección de basura, etc.
http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
TargetOfInvocationNullException
.Mírelo de esta manera: ¿es más eficiente tirar la basura de la cocina cuando el bote de basura está al 10% o dejar que se llene antes de sacarlo?
Al no dejar que se llene, está perdiendo el tiempo caminando hacia y desde el contenedor de basura afuera. Esto es análogo a lo que sucede cuando se ejecuta el subproceso de GC: todos los subprocesos administrados se suspenden mientras se ejecuta. Y si no me equivoco, el subproceso GC se puede compartir entre múltiples AppDomains, por lo que la recolección de basura los afecta a todos.
Por supuesto, es posible que encuentre una situación en la que no agregará nada a la basura en el corto plazo, por ejemplo, si se va a tomar unas vacaciones. Entonces, sería una buena idea tirar la basura antes de salir.
Esta PUEDE ser una ocasión en la que forzar un GC puede ayudar: si su programa está inactivo, la memoria en uso no se recolecta como basura porque no hay asignaciones.
fuente
La mejor práctica es no forzar la recolección de basura en la mayoría de los casos. (Todos los sistemas en los que he trabajado que tenían recolecciones de basura forzadas, tenían problemas de subrayado que, de ser resueltos, habrían eliminado la necesidad de forzar la recolección de basura y aceleraron enormemente el sistema).
Hay algunos casos en los que sabe más sobre el uso de la memoria que el recolector de basura. Es poco probable que esto sea cierto en una aplicación multiusuario o en un servicio que responde a más de una solicitud a la vez.
Sin embargo, en algunos tipos de procesamiento por lotes , sabe más que el GC. Por ejemplo, considere una aplicación que.
Es posible que pueda hacer un caso (después de una prueba cuidadosa) de que debe forzar una recolección de basura completa después de haber procesado cada archivo.
Otro caso es un servicio que se activa cada pocos minutos para procesar algunos elementos y no mantiene ningún estado mientras está inactivo . Entonces puede valer la pena forzar una colección completa justo antes de irse a dormir .
Preferiría tener una API de recolección de basura cuando podría darle pistas sobre este tipo de cosas sin tener que forzar un GC yo mismo.
Ver también " Tidbits de rendimiento de Rico Mariani "
fuente
Creo que el ejemplo dado por Rico Mariani fue bueno: puede ser apropiado activar un GC si hay un cambio significativo en el estado de la aplicación. Por ejemplo, en un editor de documentos, puede estar bien activar un GC cuando se cierra un documento.
fuente
Hay pocas pautas generales en la programación que sean absolutas. La mitad de las veces, cuando alguien dice 'lo estás haciendo mal', simplemente está lanzando una cierta cantidad de dogma. En C, solía ser miedo a cosas como el código o los subprocesos que se modifican automáticamente, en los lenguajes de GC es forzar el GC o, alternativamente, evitar que el GC se ejecute.
Como es el caso con la mayoría de las pautas y las buenas reglas empíricas (y las buenas prácticas de diseño), hay raras ocasiones en las que tiene sentido trabajar en torno a la norma establecida. Debe estar muy seguro de que comprende el caso, de que su caso realmente requiere la abrogación de la práctica común y de que comprende los riesgos y efectos secundarios que puede causar. Pero existen tales casos.
Los problemas de programación son muy variados y requieren un enfoque flexible. He visto casos en los que tiene sentido bloquear GC en lenguajes de recolección de basura y lugares donde tiene sentido activarlo en lugar de esperar a que ocurra de forma natural. El 95% de las veces, cualquiera de estos sería un indicador de no haber abordado correctamente el problema. Pero 1 vez de cada 20, probablemente haya un caso válido para hacerlo.
fuente
He aprendido a no intentar burlarme de la recolección de basura. Dicho esto, me limito a usar
using
palabras clave cuando trato con recursos no administrados como E / S de archivos o conexiones de bases de datos.fuente
No estoy seguro de si es una buena práctica, pero cuando trabajo con grandes cantidades de imágenes en un bucle (es decir, creando y eliminando muchos objetos Gráficos / Imagen / Mapa de bits), dejo que GC.Collect.
Creo que leí en alguna parte que el GC solo se ejecuta cuando el programa está (en su mayoría) inactivo, y no en medio de un ciclo intensivo, por lo que podría parecer un área donde el GC manual podría tener sentido.
fuente
Un caso que encontré recientemente que requirió llamadas manuales
GC.Collect()
fue cuando trabajaba con objetos grandes de C ++ que estaban empaquetados en pequeños objetos administrados de C ++, a los que a su vez se accedía desde C #.Nunca se llamó al recolector de basura porque la cantidad de memoria administrada utilizada fue insignificante, pero la cantidad de memoria no administrada utilizada fue enorme. Llamar manualmente
Dispose()
a los objetos requeriría que yo mismo realice un seguimiento de cuándo los objetos ya no son necesarios, mientras que la llamadaGC.Collect()
limpiará cualquier objeto que ya no se haga referencia ...fuente
GC.AddMemoryPressure (ApproximateSizeOfUnmanagedResource)
al constructor y luegoGC.RemoveMemoryPressure(addedSize)
al finalizador. De esta forma, el recolector de basura se ejecutará automáticamente, teniendo en cuenta el tamaño de las estructuras no administradas que se podrían recolectar. stackoverflow.com/questions/1149181/…Creo que ya enumeraste las mejores prácticas y NO debes usarlas a menos que REALMENTE sea necesario. Recomendaría encarecidamente mirar su código con más detalle, utilizando potencialmente herramientas de creación de perfiles si es necesario para responder a estas preguntas primero.
fuente
Suponga que su programa no tiene pérdida de memoria, los objetos se acumulan y no pueden ser GC-ed en Gen 0 porque: 1) Se hace referencia a ellos durante mucho tiempo, así que acceda a Gen1 y Gen2; 2) Son objetos grandes (> 80K) así que entra en LOH (Large Object Heap). Y LOH no compacta como en Gen0, Gen1 y Gen2.
Compruebe el contador de rendimiento de ".NET Memory", si puede ver que 1) el problema no es realmente un problema. Generalmente, cada 10 GC Gen0 activará 1 GC Gen1, y cada 10 GC Gen1 activará 1 GC Gen2. En teoría, GC1 y GC2 nunca pueden ser GC-ed si no hay presión sobre GC0 (si el uso de la memoria del programa está realmente cableado). Nunca me pasa a mí.
Para el problema 2), puede comprobar el contador de rendimiento ".NET Memory" para verificar si LOH se está hinchando. Si realmente es un problema para su problema, tal vez pueda crear un grupo de objetos grandes como sugiere este blog http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx .
fuente
Los objetos grandes se asignan en LOH (montón de objetos grandes), no en la generación 0. Si está diciendo que no se recolectan basura con la generación 0, tiene razón. Creo que se recopilan solo cuando ocurre el ciclo completo de GC (generaciones 0, 1 y 2).
Dicho esto, creo que, por otro lado, GC se ajustará y recopilará memoria de manera más agresiva cuando trabaje con objetos grandes y la presión de la memoria esté aumentando.
Es difícil decir si cobrar o no y en qué circunstancias. Solía hacer GC.Collect () después de deshacerme de las ventanas / formularios de diálogo con numerosos controles, etc. (porque para cuando el formulario y sus controles terminan en la generación 2 debido a la creación de muchas instancias de objetos comerciales / carga de muchos datos, no objetos grandes obviamente), pero en realidad no notó ningún efecto positivo o negativo a largo plazo al hacerlo.
fuente
Me gustaría agregar que: Llamar a GC.Collect () (+ WaitForPendingFinalizers ()) es una parte de la historia. Como han mencionado correctamente otros, GC.COllect () es una colección no determinista y se deja a la discreción del propio GC (CLR). Incluso si agrega una llamada a WaitForPendingFinalizers, es posible que no sea determinista. Tome el código de este enlace msdn y ejecute el código con la iteración del bucle del objeto como 1 o 2. Encontrará qué significa no determinista (establezca un punto de interrupción en el destructor del objeto). Precisamente, el destructor no se llama cuando solo había 1 (o 2) objetos persistentes por Wait .. (). [Req. Cita]
Si su código está tratando con recursos no administrados (por ejemplo: identificadores de archivos externos), debe implementar destructores (o finalizadores).
Aquí hay un ejemplo interesante:
Nota : Si ya ha probado el ejemplo anterior de MSDN, el siguiente código aclarará las cosas.
Sugiero, primero analice cuál podría ser la salida y luego ejecute y luego lea el motivo a continuación:
{El destructor solo se llama implícitamente una vez que finaliza el programa. } Para limpiar determinísticamente el objeto, uno debe implementar IDisposable y hacer una llamada explícita a Dispose (). ¡Esa es la esencia! :)
fuente
Una cosa más, activar GC Collect de forma explícita NO puede mejorar el rendimiento de su programa. Es muy posible que empeore.
El .NET GC está bien diseñado y ajustado para ser adaptable, lo que significa que puede ajustar el umbral GC0 / 1/2 de acuerdo con el "hábito" de uso de la memoria de su programa. Por lo tanto, se adaptará a su programa después de un tiempo de ejecución. Una vez que invoque GC.Collect explícitamente, ¡los umbrales se restablecerán! Y .NET tiene que dedicar tiempo a adaptarse nuevamente al "hábito" de su programa.
Mi sugerencia es confiar siempre en .NET GC. Si surge algún problema de memoria, compruebe el contador de rendimiento ".NET Memory" y diagnostique mi propio código.
fuente
Sugerencia: no implemente esto ni nada cuando no esté seguro. Reevalúe cuando se conozcan los hechos, luego realice pruebas de desempeño antes / después para verificar.
fuente
En mi humilde opinión, esto es similar a decir "Si puede demostrar que su programa nunca tendrá ningún error en el futuro, entonces adelante ..."
Con toda seriedad, forzar el GC es útil para fines de depuración / prueba. Si siente que necesita hacerlo en cualquier otro momento, entonces está equivocado o su programa se ha construido mal. De cualquier manera, la solución no es forzar el GC ...
fuente