2010-04-26 14 views
12

OK aquí está el trato. Hay algunas personas que ponen sus vidas en manos del recolector de basura de .NET y algunos que simplemente no confían en él.Eficiencia del recolector de basura .NET

Soy uno de los que confía parcialmente en él, siempre que no sea extremadamente crítico para el rendimiento (sé que sé ... rendimiento crítico + .net no es la combinación preferida), en cuyo caso prefiero deshacerme manualmente de mi objetos y recursos.

Lo que estoy preguntando es si hay datos sobre cuán eficiente o ineficiente es el rendimiento del recolector de basura en realidad.

Por favor, no comparta ninguna opinión personal o posible hipótesis basada en la experiencia, quiero hechos imparciales. Tampoco quiero discusiones pro/con porque no responderá la pregunta.

Gracias

Editar: Para aclarar, básicamente lo que digo: No importa qué aplicación se escribe, recurso crítico o no pueden simplemente olvidarse de todo y dejar que el GC manejarlo o no nosotros ?

Estoy tratando de obtener una respuesta en realidad sobre lo que el GC hace y no hace y dónde podría fallar donde la gestión de memoria manual sería exitosa SI existen tales escenarios. ¿Tiene LIMITACIONES? No sé cómo podría explicar mi pregunta aún más.

No tengo ningún problema con ninguna aplicación, es una pregunta teórica.

+6

define eficiente. sin saber cómo se quiere medir su eficiencia, es difícil responder a eso. –

+0

Bueno, si es posible trate de evitar parientes o si debe, compárelo con una gestión de memoria manual impecable. –

+0

Si está buscando hechos imparciales, ¿por qué no realiza algunas pruebas usted mismo? Ejecutar a través de una creación y la destrucción manual, y luego ejecutar el mismo programa de nuevo sin deshacerse de nada y dejar que el GC lo recoja? Si desea que los números y las pruebas anecdóticas no le sirvan, configure las pruebas para obtener los números usted mismo. – SqlRyan

Respuesta

9

es lo suficientemente eficiente para la mayoría de las aplicaciones. Pero no tienes que vivir con miedo a GC. En sistemas muy calientes, bajos requisitos de latencia, debe programar de una manera que lo evite por completo. Le sugiero que busque en este Rapid Addition White Paper:

Aunque GC se realiza bastante rápidamente, toma tiempo para llevar a cabo, y por lo tanto la recolección de basura en su modo de funcionamiento continuo puede introducir tanto la latencia indeseable y variación en latencia en las aplicaciones que son altamente sensibles a la demora. A modo de ejemplo , si está procesando 100.000 mensajes por segundo y cada mensaje utiliza una pequeña cadena temporal 2 carácter, alrededor de 8 bytes (este una función de la cadena de codificación y la implementación del objeto de cadena) se asigna para cada mensaje Por lo tanto, está creando casi 1MB de basura por segundo. Para un sistema que puede tener un rendimiento constante durante un período de 16 horas, esto significa que tendrá que limpiar 16 horas x 60 minutos x 60 segundos x 1 MB de memoria aproximadamente 56 GB de memoria. Lo mejor que se puede esperar del colector basura es que va a limpiar esto por completo, ya sea en Generación 0 ó 1 colecciones y causa de fluctuación, lo peor es que provocará una generación 2 recolección de basura con el asociado más grande punto de latencia.

pero ten cuidado, tirando de trucos tales como evitar el impacto GC es muy difícil . Realmente necesita reflexionar si se encuentra en ese momento en sus requisitos de rendimiento donde debe considerar el impacto de GC.

+0

Muchas gracias por esa información, realmente lo aprecio. –

+0

Eso fue una lectura interesante y respondió muchas de mis preguntas, gracias de nuevo. –

1

Cualquier algoritmo de GC favorecerá cierta actividad (es decir, la optimización). Deberá probar el GC contra su patrón de uso para ver qué tan eficiente es para usted. Incluso si alguien más estudiara el comportamiento particular del .net GC y produjera "hechos" y "números", sus resultados podrían ser muy diferentes.

Creo que la única respuesta razonable a esta pregunta es anecdótica. La mayoría de las personas no tienen problemas con la eficiencia de GC, incluso en situaciones de gran escala. Se considera al menos tan eficiente o más eficiente que los GC de otros lenguajes administrados. Si todavía está preocupado, probablemente no debería usar un lenguaje gestionado.

+0

Gracias por la respuesta, no es realmente una preocupación, solo creo que es algo que debe tener un poco de conocimiento, no es por eso que estoy preguntando. –

2

No necesita preocuparse por esto.

La razón es que si alguna vez encuentra una caja de borde donde el GC está ocupando una cantidad significativa de tiempo, entonces podrá manejarlo haciendo optimizaciones puntuales. Este no será el fin del mundo, probablemente será bastante fácil.

Y es poco probable que encuentre tales casos borde. Realmente funciona sorprendentemente bien. Si solo has experimentado asignadores de montón en implementaciones típicas de C y C++, el .NET GC es un animal completamente diferente. Estaba tan sorprendido por él I wrote this blog post to try and get the point across.

2

No puede siempre olvidarse de la asignación de memoria, independientemente de si utiliza un GC o no. Lo que una buena implementación de GC le compra es que la mayor parte del tiempo puede permitirse no pensar en la asignación de memoria. Sin embargo, no hay un asignador de memoria definitivo. Para algo crítico, debes ser consciente de cómo se maneja la memoria, y esto implica saber cómo se hacen las cosas internamente. Esto es cierto tanto para GC como para la asignación manual del montón.

Hay son algunos GC que ofrecen garantías en tiempo real. "Tiempo real" no significa "rápido", significa que el tiempo de respuesta del asignador puede estar limitado. Este es el tipo de garantía que se necesita para sistemas integrados como los que manejan comandos eléctricos en un avión. Curiosamente, es más fácil tener garantías en tiempo real con recolectores de basura que con asignadores manuales.

El GC en las implementaciones actuales de .NET es no en tiempo real; son heurísticamente eficientes y rápidos. Tenga en cuenta que puede decirse lo mismo sobre la asignación manual con malloc() en C (o new en C++), por lo tanto, si busca garantías en tiempo real, necesita usar algo especial. Si no lo hace, ¡no quiero que diseñe los componentes electrónicos integrados para los automóviles y aviones que uso!

5

Le puedo contar algunos de los problemas que he tenido con el recolector de basura de .NET.

Si está ejecutando una aplicación que utiliza el servidor de catálogo global (por ejemplo, una aplicación ASP.NET), entonces su latencia será verdaderamente horrible , con pausas de alrededor de un segundo cuando ninguno de los hilos puede hacer ningún progreso en todas. Esto se debe a que el servidor .NET 4 GC es un GC stop-the-world. Aparentemente, .NET 4.5 introducirá el primer servidor de GC concurrente de Microsoft.

Una vez escribí un código de instrumentación para medir las latencias en un sistema simultáneo utilizando colecciones integradas como ConcurrentBag y me quedé sin memoria en 32 bits debido a la fragmentación masiva del montón porque .NET GC no desfragmenta objetos grandes . Tuve que reemplazar las estructuras de datos basadas en arreglos con estructuras de datos puramente funcionales que están diseminadas en millones de piezas pequeñas para evitar tener algo en el Montículo de objetos grandes (LOH) que estaba causando la fragmentación.

He encontrado errores en el GC como this one que hace que el GC a perder memoria hasta que se agota toda la memoria del sistema con que el montón se borra en un gran ciclo de GC que las pausas no sólo todos sus hilos, pero incluso otros procesos (porque el sistema se ha ido a cambiar) durante varios minutos.

Aunque hay una configuración de "baja latencia" en el último .NET GC, en realidad solo desactiva la recolección de elementos no utilizados, por lo que su programa pierde memoria hasta que obtiene una pausa masiva del GC. Microsoft parece preferir soluciones como esta que son equivalentes a decir "escriba su propio recolector de basura si desea latencia utilizable".

Sin embargo, el .NET GC es generalmente muy bueno y, cuando se usa con cuidado, es posible obtener buenos resultados. Por ejemplo, recientemente escribí un servidor tolerante a fallas que alcanza una latencia puerta a puerta de 114 μs en promedio con un 95% de latencias por debajo de 0,5 ms. Eso es impresionantemente cercano al estado del arte (ver here y here) dado que escribí toda la plataforma en F # por mí mismo en solo unos pocos meses. La red en realidad contribuyó más a la latencia que la .NET GC.

+0

¡Esa es una lectura interesante, gracias! También leeré en los enlaces que publicaste :) –

+1

Puedo confirmar que 'SustainedLowLatency' realmente solo apaga GC. Esto fue todo un shock, después de que recibí 'OutOfMemoryException's, pero en general resultó que funcionaba bien, ya que no quería latencia casi cuando lo necesitaba, pero podía tolerar pausas cada pocos minutos. Luego volví a 'Concurrent' y dejé la limpieza del GC antes de volver a apagarlo. – codekaizen

Cuestiones relacionadas