2012-01-05 9 views
7

En un título "Forzando una Colección de basura" del libro "C# .NET 2010 y el 4 Plataforma" por Andrew Troelsen escrito:recolección de elementos indeseables

"Una vez más, todo el propósito de la .NET El recopilador de basura debe administrar la memoria en nuestro nombre. Sin embargo, en algunas circunstancias excepcionales, puede ser beneficioso forzar programáticamente una recolección de basura mediante GC.Collect(). Específicamente:

• Su aplicación está a punto de entrar en una bloque de código que no desea interrumpir por una posible recolección de basura. ... "

¡Pero detente! ¿Hay un caso así cuando la recolección de basura no es deseable? Nunca vi/leí algo así (debido a mi poca experiencia de desarrollo, por supuesto). Si mientras practicas has hecho algo así, por favor comparte. Para mí es un punto muy interesante.

¡Gracias!

+7

Tome nota especial de * "algunas circunstancias muy raras" * y no rocíe GC.Collect() en todo su código. –

+0

¡Se hará! :) – Arterius

Respuesta

5

Corro un sitio web relacionado con recetas, y almaceno un enorme gráfico de recetas y su uso de ingredientes en la memoria. Debido a la forma en que pivoto esta información para un acceso rápido, tengo que cargar varios gigas de datos en la memoria cuando la aplicación se carga antes de poder organizar los datos en un gráfico muy optimizado. Creo una gran cantidad de pequeños objetos en el montón que, una vez que se construye el gráfico, se vuelven inalcanzables.

Todo esto se hace cuando se carga la aplicación web, y probablemente tome entre 4 y 5 segundos. Después de hacerlo, llamo al GC.Collect(); porque preferiría volver a reclamar toda esa memoria ahora en lugar de bloquear potencialmente todos los hilos durante una solicitud HTTP entrante, mientras que el recolector de basura está volviendo loco limpiando todos estos objetos efímeros.También creo que es mejor limpiar ahora ya que el montón probablemente esté menos fragmentado en este momento, ya que mi aplicación realmente no ha hecho nada más hasta el momento. Al retrasar esto, es posible que se creen muchos más objetos y que el montón tenga que comprimirse más cuando el GC se ejecute automáticamente.

Aparte de eso, en mis 12 años de programación con .NET, nunca me he encontrado con una situación en la que quisiera forzar la ejecución del recolector de basura.

7

Sí, hay absolutamente un caso cuando la recolección de basura no es deseable: cuando un usuario está esperando que ocurra algo, y tienen que esperar más porque el código no puede continuar hasta que se complete la recolección de basura.

Ese es el punto de Troelsen: si tiene un punto específico donde se sabe que un GC no es problemática y es probable que sea capaz de recoger grandes cantidades de basura entonces puede ser una buena idea para provocar entonces, para evitar que se dispare en un momento menos oportuno.

+0

Cuando sabes que no es problemático, incluso más raro que los escenarios en los que es posible que desees ... –

+0

@TonyHopkinson: Es relativamente raro, pero no desconocido. Más exactamente, es posible que sepa que es * menos * problemático ahora de lo que sería pronto. –

+0

Siempre hay una razón para romper las reglas, sin argumentar que nunca debes hacer eso, solo que antes de romperlas, debes entenderlas, para que puedas romperlas efectivamente. –

1

Sería muy raro, pero GC puede ser un proceso moderadamente costoso, por lo que si hay una sección en particular que es sensible al tiempo, no querrá que esa sección interrumpa el GC.

3

La recomendación es que no debe llamar explícitamente Collect en su código. ¿Puedes encontrar circunstancias donde sea útil?

Otros han detallado algunos, y no hay duda más. Sin embargo, lo primero que debes entender es , no lo hagas. Es un último recurso, investigue otras opciones, aprenda cómo funciona GC cómo se afecta su código, siga las mejores prácticas para sus diseños.

Llamar a Collect en el punto incorrecto empeorará su rendimiento. Peor aún, confiar en él hace que su código sea muy frágil. Las raras condiciones requeridas para hacer una llamada al Collect son beneficiosas, o al final no dañinas, pueden deshacerse por completo con un simple cambio en el código, lo que dará como resultado OOMs inesperados, rendimiento lento y tal.

2

Lo llamo antes de las mediciones de rendimiento para que el GC no falsifique los resultados.

Otra situación son las pruebas de unidad de pruebas de fugas de memoria:

object doesItLeak = /*...*/; //The object you want to have tested 
WeakReference reference = new WeakRefrence(doesItLeak); 
GC.Collect(); 
GC.WaitForPendingFinalizers(); 
GC.Collect(); 

Assert.That(!reference.IsAlive); 

Además de ellos, no me encontré con una situación en la que en realidad sería útil.
Especialmente en el código de producción, GC.Collect nunca se debe encontrar en mi humilde opinión.

1

Su aplicación está a punto de ingresar a un bloque de código que usted no quiere interrumpir por una posible recolección de basura. ...

Un argumento muy sospechoso (que sin embargo se usa mucho).

Windows no es un sistema operativo en tiempo real. Su código (Thread/Process) siempre puede ser anulado por el programador del sistema operativo. No tiene un acceso garantizado a la CPU.

Por lo tanto, se reduce a: ¿cómo se compara el tiempo para una ejecución de GC con un intervalo de tiempo (~ 20 ms)?

Hay muy pocos datos duros disponibles al respecto, he buscado algunas veces.

Según mi propia observación (muy informal), una colección gen-0 es < 40 ms, generalmente mucho menos. Un gen-2 completo puede ejecutarse en ~ 100 ms, probablemente más.

Por lo tanto, el "riesgo" de ser interrumpido por el GC es del mismo orden de magnitud que el cambio para otro proceso. Y no puedes controlar lo segundo.

Cuestiones relacionadas