2009-06-10 14 views
10

Mi aplicación asigna una gran cantidad de memoria (millones de objetos pequeños que suman varios gigabytes) y la retiene durante mucho tiempo.Supresión de la recolección de basura C#

  1. ¿Está .NET perdiendo el tiempo comprobando todos estos datos para hacer GC en él?
  2. ¿Con qué frecuencia se produce el Gen 2 GC (el que verifica todos los objetos)?
  3. ¿Hay alguna forma de reducir su frecuencia o suprimirla temporalmente?
  4. Sé exactamente cuándo estoy listo para recolectar una gran cantidad de memoria, ¿hay alguna manera de optimizarlo? Actualmente estoy llamando a GC.Collect(); GC.WaitForPendingFinalizers(); En ese tiempo.

Actualización: Cuenta de resultados "% Time in GC" muestra un promedio de 10.6%.

+0

Esa línea de código solo se activa cada 3 minutos, por lo que probablemente no tenga mucho impacto. – Fantius

+1

Preguntas relacionadas: [Prevenir la recolección de elementos no deseados de .NET durante un breve período de tiempo] (http://stackoverflow.com/questions/6005865), [¿Cómo evitar la recolección de elementos no utilizados en la aplicación .NET en tiempo real?] (Http: // stackoverflow .com/questions/85283) –

Respuesta

23

A menos que pueda confirmar que el recolector de elementos no utilizados está frenando activamente el rendimiento de su aplicación, no debe tomar medidas para paralizar la funcionalidad de su entorno de tiempo de ejecución.

A juzgar por su pregunta, no ha confirmado que el GC sea un problema. Dudo mucho de que lo sea.

Optimice solo lo que necesita optimizarse.

+3

El contador de rendimiento "% de tiempo en GC" muestra un promedio de 10.6%. – Fantius

+0

Si su aplicación se agita en muchos objetos, se espera que tenga un tiempo de GC más alto. Si escribiera el mismo código en C++, tendría casi tanto tiempo dedicado a asignar, poner a cero y liberar trozos de memoria de todos modos, tal vez más tiempo dependiendo de la eficiencia de su administrador de memoria. – jrista

+1

Por lo tanto, dado que estoy asignando millones de la misma clase exacta y luego liberando una gran parte de todos al mismo tiempo, ¿hay un patrón mejor para seguir que el típico descarte nuevo? – Fantius

3

Solo ocurrirá (normalmente) cuando el GC necesite algo de memoria gen2 de todos modos (porque gen1 está lleno). ¿Estás preguntando esto de forma especulativa, o realmente tienes un problema con GC tomando una gran parte de tu tiempo de ejecución? Si no tienes un problema, te sugiero que no te preocupes por el momento, pero mantenlo vigilado con monitores de rendimiento.

+1

¿Soy incorrecto al pensar que el GC está comprobando si los "punteros" están en uso (o con qué frecuencia se usan), y no se preocupa por el tamaño de cada objeto individual? – DevinB

+1

Por lo que sé, sí. Por otro lado, si tiene menos objetos grandes, tomará menos tiempo para marcar/barrer que millones de objetos pequeños. Sin embargo, trataría de evitar que esto influya en tu diseño. –

+0

No debe influir en su diseño a menos que tenga una decisión 50/50, en cuyo caso debería elegir la opción que es más fácil de optimizar. Asumiendo que la legibilidad y otros factores son iguales. Siempre es mejor tener más información, en mi opinión. – DevinB

9

Mire la propiedad System.Runtime.GCSettings.LatencyMode.

Establecer la propiedad GCServer en verdadero en la aplicación.config también ayudará a reducir los GC (en mi caso, 10 veces menos GC cuando está habilitado).

+0

Lo configuré para LowLatency pero no observé ninguna mejora. – Fantius

+0

GCLatencyMode.SustainedLowLatency me ayudó mucho a mejorar la capacidad de respuesta de un bucle rápido de procesamiento de señal de casi RT, gracias. – metao

9

puede detener el recolector de basura de la finalización de cualquiera de sus objetos usando el método estático:

GC.SuppressFinalize(*your object*) 

Más información aquí: link text

+1

Eso invitaría a pérdidas de recursos y no aborda la cuestión. –

+0

Sí, eso invita a pérdidas de recursos, pero de hecho aborda la cuestión de alguna manera si usted sabe cómo funciona realmente la finalización. – Joshua

+0

Respondí a la pregunta original: ha cambiado desde entonces. Originalmente estaba preguntando cómo evitar que el GC verifique sus objetos grandes. Si esa es una buena idea o no, es una cuestión diferente. –

7

Usted puede medir esto utilizando Monitor de rendimiento. Abra perfmon y agregue los contadores de rendimiento relacionados con .NET CLR Memory. Estos contadores son específicos del proceso y con ellos puede realizar un seguimiento del número de colecciones y tamaños de las distintas generaciones y, más específicamente, del "% de tiempo en GC". He aquí el texto de explicar para este contador:

% Tiempo en GC es el porcentaje de tiempo transcurrido que se gastó en realizar una recolección de basura (GC) desde el último ciclo de GC. Este contador suele ser un indicador del trabajo realizado por Garbage Collector en en nombre de la aplicación para recopilar y memoria compacta. Este contador es actualizado solo al final de cada GC y el valor del contador refleja el último valor observado; no es un promedio de .

Si mira estos contadores mientras ejecuta su programa, debe tener respuesta para la frecuencia y el costo del GC debido a sus decisiones de memoria.

Here es una buena discusión de los diversos contadores de rendimiento de GC. Parece que el 10% está en el límite correcto.

1

Mi aplicación ASP.NET - sistema B2B - solía comenzar en 35-40MB cuando llegó el primer usuario. Después de tantos minutos, la aplicación solía crecer hasta 180 MB con 2 o 3 usuarios golpeando páginas. Después de leer las mejores prácticas de desarrollo .net y la guía de rendimiento de GC, descubro que el problema era el diseño de mi aplicación. No estuve de acuerdo de una vez.

Estaba horrorizado de lo fácil que podemos hacer los errores. Renuncié a muchas características y comencé a facilitar algunos objetos. Significado:

  1. evitar mezclar tanto las páginas y controles de usuario inteligentes y comunicativos (las que tienen gran cantidad de funcionalidades que en realidad la mayoría existir para cada página que utiliza este control).

  2. Dejar de generar funcionalidades universales en las clases base. Algunas veces es preferible repetir. La herencia es costo

  3. En algunas funciones complejas pongo todo en la misma función. SÍ, llegando a 100 líneas más. Cuando leí esta recomendación sobre la guía de rendimiento de .net, no lo creí pero funciona. Las pilas de llamadas son un problema, el uso de propiedades de clase sobre las variables locales es un problema. Las variables de nivel de clase pueden ser un infierno ...

  4. Deje de usar clases base complejas, no debe haber clases base con más de 7 líneas. Si expandes clases más grandes en todo el framework, tendrás problemas.

  5. Comienzo a usar más objetos estáticos y funcionalidades. Vi la aplicación que el otro chico diseñó. Todos los métodos de objetos de acceso a datos (insertar, actualizar, eliminar, seleccionar) eran estáticos. La aplicación con más usuarios simultáneos nunca llega a más de 45 MB.

  6. Para guardar algunos proyectos, me gusta el patrón de estado de reposo. Aprendí en el mundo real, pero el autor Nygard también está de acuerdo conmigo en su libro: Release IT - Diseñe e implemente software de producción preparada. Él llama a tal enfoque como un patrón de estado estable. Este patrón dice que podemos necesitar algo para liberar recursos inactivos.

  7. Es posible que desee jugar con el archivo de configuración de la máquina. En el atributo memoryLimit, indicará el porcentaje de memoria que podría alcanzarse antes de que un proceso se recicle.

  8. Es posible que también quiera jugar en el archivo de configuración de la máquina. En este atributo, GC dictará el comportamiento de la máquina (Workstation GC y Server GC). Esta opción también puede cambiar drásticamente el comportamiento de consumo de la memoria.

Tuve mucho éxito cuando empecé a preocuparme por estos artículos. Espero que esto ayude.

- EDITADO EN 04-05-2014 He cambiado de opinión sobre muchas cosas debido a las mejoras de las nuevas versiones de GC y los avances de HTML 5 y MVC framework.

+0

Mi aplicación no se trata de usuarios concurrentes. Y no creo que esté usando ninguna herencia. No hay controles de usuario. Cada vez que algo puede ser estático, lo hago estático. Mi proceso nunca se recicla. – Fantius

Cuestiones relacionadas