2011-05-26 11 views
20

Tengo una situación extraña que estoy tratando de resolver.¿Qué desencadena una recolección de basura gen2?

El Génesis:

estoy corriendo mi programa en una máquina física con núcleos y 128 GB de RAM. Estoy tratando de determinar por qué no está utilizando todos los núcleos disponibles, por lo general utiliza un 20-25% de CPU en promedio (por lo que 4-5 núcleos de los 16). Cuando miro los contadores de rendimiento, se muestran en el orden de 60-70% de tiempo en la recolección de basura.

Como referencia, estoy usando .NET Framework 4 y el TPL (Parallel.ForEach) para enhebrar la parte de mi programa que requiere mucho rendimiento. Estoy limitando la cantidad de hilos a la cantidad de núcleos.

El problema:

estaba creando un gran número de objetos, demasiados para el recolector de basura para manejar de manera eficiente y por lo tanto, pasé una gran cantidad de tiempo en el recolector de basura.

La solución más sencilla hasta la fecha:

estoy presentando la agrupación de objetos para reducir la presión en el colector de basura. Continuaré agrupando objetos para mejorar el rendimiento, ya que la agrupación de algunos objetos redujo la recolección de basura del 60-70% del tiempo al 45% del tiempo y mi programa se ejecutó un 40% más rápido.

La Persistente pregunta (la que espero que responder por mí):

Mi programa cuando se ejecuta usos como máximo 14 GB de la memoria RAM disponible, en comparación con 128 GB de RAM esto es bastante pequeña. Nada más se está ejecutando en esta máquina (es simplemente un banco de pruebas para mí) y hay mucha RAM disponible.

  • Si hay suficiente RAM disponible, ¿por qué se producen colecciones gen2 (o completas)? Se está produciendo una cantidad bastante grande de estas colecciones gen2 (en miles). es decir, cómo determina el umbral para iniciar una colección gen2?
  • ¿Por qué el recolector de basura simplemente no demora ninguna colección completa hasta que la presión en la RAM física alcanza un umbral más alto?
  • ¿Hay alguna manera en que pueda configurar el recolector de elementos no utilizados para esperar un umbral más alto? (Es decir, no se molestan en absoluto si la recogida no es necesario)

EDIT:

ya estoy usando la opción de utilizar el recolector de basura servidor ... lo que necesito saber es lo que está provocando una gen2 collection, no es que el recolector de basura del servidor sea mejor (ya lo sé).

Respuesta

19

Como recuerdo, el Cliente GC es el predeterminado. Mi experiencia con esto es que no permite que el montón sea muy grande antes de recolectar. Para mis aplicaciones de procesamiento de trabajo pesado, utilizo el GC "servidor".

habilita el servidor de GC en el archivo de configuración de la aplicación:

<?xml version ="1.0"?> 
<configuration> 
    <runtime> 
    <gcServer enabled="true"/> 
    </runtime> 
</configuration> 

Eso hace una diferencia enorme en el rendimiento para mí. Por ejemplo, uno de mis programas estaba gastando más del 80% de su tiempo en la recolección de basura. La habilitación del GC del servidor se redujo a poco más del 10%. El uso de memoria subió porque el GC lo dejó pasar, pero eso está bien para la mayoría de mis aplicaciones.

Otra cosa que causará una colección Gen 2 es el gran montón de objetos. Ver CLR Inside Out: Large Object Heap Uncovered. En pocas palabras, si excedes el umbral LOH, activará una colección Gen 2. Si está asignando una gran cantidad de objetos grandes de corta vida (alrededor de 85 kilobytes), esto será un problema.

+0

Ya estoy usando el recolector de basura del servidor (es más eficiente con muchos núcleos debido a la regla de un montón por núcleo). Aunque aprecio su sugerencia útil, eso realmente no respondió mi pregunta :( –

+0

@Jeffrey: Vea mi edición sobre el Montículo de Objetos Grandes. –

+0

Ese es un buen punto.Aunque no creo que esté haciendo eso, mi montón de LOH normalmente tiene solo una matriz pero voy a profundizar un poco más en eso. –

5

De memoria vaga y teniendo una lectura: http://msdn.microsoft.com/en-us/library/ee787088.aspx, creo que un gatillo de un Gen 2 GC puede ser un segmento de Gen 2 que se llena. El artículo indica que Server GC utiliza segmentos más grandes, por lo que como ya se señaló, esto es probablemente importante para su rendimiento.

Tener la máquina esperando hasta que prácticamente no haya memoria significa que obtendrá un infierno de un GC en algún momento. Esto probablemente no es ideal. Si su tiempo en GC es tan alto, es una señal de que está asignando demasiados objetos que están sobreviviendo el tiempo suficiente para pasar el gen 0 & 1, y hacerlo de manera repetitiva. Si el uso de memoria de su aplicación no aumenta con el tiempo, esto indica que estos objetos son en realidad de corta duración, pero que viven lo suficiente como para sobrevivir a una colección de 0 y 1. Esta es una mala situación: está asignando un objeto efímero pero pagando un costo total de la colección Gen 2 para limpiarlo.

Si ese es el caso, tienes unas pocas direcciones diferentes para tomar:

  1. tratar de hacer que los objetos cortos duración del coleccionable de antes (por lo que no llegan a Gen 2 y por lo tanto el costo de GC es lower)
  2. Trate de asignar menos objetos de vida corta (para que los GC ocurran con menos frecuencia y tenga más tiempo para terminar utilizando objetos de corta vida antes de que las asignaciones fuercen un GC y los objetos se muevan a generaciones anteriores)
  3. Use stack assigned value tipos en lugar de tipos de referencia para los objetos efímeros (si corresponde a su propósito)
  4. Si sabe que necesita una gran cantidad de estos objetos, agrúpelos por adelantado. Parece que estás haciendo esto, pero aún debe haber mucha asignación para mantener el GC en un 45%. Si su grupo no es lo suficientemente grande, asigne más por adelantado, como usted dice, tiene mucha memoria extra.

Es probable que una combinación de todos estos sea una buena solución. Debe comprender bien qué objetos está asignando, cuánto tiempo están viviendo y cuánto tiempo realmente necesitan vivir para cumplir con su propósito.

El GC está contento con los objetos temporales que tienen vidas cortas (como son coleccionables por el GC rápidamente), o obects permanentes o de larga duración que tienen vidas largas. La asignación de muchos objetos en el medio de esas dos categorías es donde obtiene el dolor. Así que asigne menos de ellos o cambie sus tiempos de vida para que coincida con su escenario de uso.

Cuestiones relacionadas