2009-05-07 24 views
14

¿Es posible establecer un tamaño mínimo de un montón de generación 0 en .NET?.NET generation 0 montón

Tengo una continuación de sistuation. Tengo una función que asigna alrededor de 20-30 MB de objetos de 1KB, hace algo con ellos y finaliza, dejando todos los objetos asignados para ser GC-ed. Ahora, en el Monitor de rendimiento, puedo ver que el tamaño de almacenamiento de la generación 0 es de 5-6 MB, que no es suficiente para aceptar todos los 20-30 MB de objetos que necesito. Cuando empiezo a asignar, en algún momento gen0 GC comienza a ejecutarse, y dado que se necesitan todos los objetos, los promueve a gen1. La próxima vez que GC comience a funcionar, estos objetos serán promovidos en gen2. Entonces, finalmente, alrededor de 15 MB de mis objetos terminan en el gen2 montón. Estos son, según mi lógica, objetos temporales que de ninguna manera deberían terminar en gen2 montón. Creo que el problema está en el tamaño del tamaño del montón gen0. Pero no estoy seguro. Sé que en Java existe la posibilidad de establecer un tamaño mínimo de los montones generacionales. ¿Hay alguna manera en .NET?

Respuesta

3

¿Estás seguro de que ya no estás haciendo referencia a estos objetos? El GC es muy bueno para ajustarse a las necesidades de su aplicación y no promocionará objetos a la Generación 2 a menos que tenga raíces para esos objetos en alguna parte.

Creo que si descubres dónde están estas raíces y te aseguras de que realmente ya no estás haciendo referencia a estos objetos en ninguna parte, el GC comenzará a liberar la memoria de esos objetos y nunca los promocionará a la Generación 1 y mucho menos a la Generación 2. También si haces esto, el GC detectará que necesitas que la Generación 0 sea más grande y aumentará el tamaño del montón en tu nombre.

+1

Los objetos mayores de 85K generalmente no son elegibles para la recolección, excepto en Gen2. Si una referencia a un nuevo objeto se almacena dentro de un objeto más grande que 85K, a menos que se destruya la referencia dentro del objeto grande, el nuevo objeto subirá a Gen2 antes de que sea elegible para la recopilación, incluso si el objeto se desenraiza antes de eso. – supercat

1

+1 a Andrew. El GC es autoajustable, aprende acerca de los patrones de necesidad de memoria de la aplicación sobre la marcha.
En su caso, si el GC realiza una recopilación de Gen 0 y encuentra que muchos objetos sobrevivieron/no se recuperó mucha memoria, el recolector de basura aumentará automáticamente el presupuesto/cuota de Gen 0.

En cuanto a GC Type members, no parece haber una forma de configurar programáticamente los presupuestos/tamaño de generación de GC.

8

El tamaño de las diferentes generaciones es un detalle de implementación, y no conozco ninguna forma de ajustarlo para las aplicaciones .NET. Si mi memoria me sirve correctamente, la generación 0 y 1 comparte un solo segmento, que es de 16 MB en Win32, por lo que si crea un montón de objetos, algunos de estos se promocionarán a generaciones superiores si todavía se referencian (al igual que tú describes).

Supongo que la idea detrás de limitar el tamaño de la generación 0 es asegurarse de que una colección g0 sea barata. Si la generación 0 puede crecer a cualquier tamaño, es probable que su rendimiento general sufra.

EDIT: Creo que el libro de Jeffrey Richter tiene algunos detalles al respecto, por lo que es posible que desee verificarlo.

EDIT2: Richter declara (p 502-507) que el presupuesto inicial de la generación 0 es de 256 KB y el presupuesto inicial de la generación 1 es de 2 MB. Sin embargo, ese no es el tamaño de la generación. Los presupuestos se ajustan según sea necesario y crecerán y disminuirán de acuerdo con el uso de la memoria de la aplicación.

Joe Duffy's Professional .NET Framework 2.0, sin embargo, establece que las generaciones ephermales (es decir, gen 0 y 1) comparten un solo segmento, que es usualmente de 16 MB (p.127). Solo la generación 2 se permite crecer según sea necesario (supongo que LOH también puede crecer según sea necesario, pero eso no me resulta claro a partir del texto).

+1

Gen 0 era 256KB (se ajusta a la memoria caché l2 de la CPU) Gen1 2MB Gen2 10MB según el segundo libro ed de Richter. Por supuesto, estos están sujetos a cambios ... – Gishu

+0

Según Richter, esos son los presupuestos de la generación 0 y 1 respectivamente. Por favor, mira mi edición para más detalles. –

3

El montón de la Generación 0 se dimensiona inicialmente a la memoria caché de su CPU.Esto es para que los pequeños objetos temporales ni siquiera necesiten moverse a la memoria principal.

+0

Actualmente estoy monitoreando una aplicación con un tamaño de almacenamiento gen0 de más de 500 mb. Por lo tanto, gen0 heap size! = Cpu cache size. – sisve

+0

Véase también http://blogs.msdn.com/b/johan/archive/2007/04/20/memory-management-in-the-net-framework.aspx. Probablemente debería editar mi respuesta para que sea más precisa. –

0

No creo que haya ninguna opción para establecer estos valores en .NET GC.

A primera vista, parece que esta situación particular justifica la necesidad de tener tal avanzaron opciones, pero si esto sería una opción estática que afectará a todo el curso de la vida de ustedes programa. Una opción dinámica, que podría establecer en tiempo de ejecución sería ideal.

Además, no creo que esto afecte enormemente el rendimiento de su programa, aunque si pudiera aumentar el tamaño del gen (0) podría liberar algo de memoria (y obtener un rendimiento de).

Dado que el GC se autoajustará, gen (0) aumentará automáticamente el tamaño y los objetos BIG terminarán siendo recogidos, tarde o temprano.

+0

la situación del OP es una gran cantidad de pequeños objetos que necesitan ser localizables al mismo tiempo ... – Gishu

3

Gracias a todos por su ayuda.

Whell, la situación es muy interesante. Nunca mencioné que estoy almacenando esos 30 MB de objetos en una matriz cuyo tamaño es 100000. Primero estoy asignando esa matriz y luego llenándola con objetos. Como esa matriz es más grande que 85K, esa matriz se almacena en el Heap de objetos grandes. Resulta que para que la recolección de basura recolecte objetos en ese montón, necesita ejecutar la colección gen2, por lo que cada vez que no hay suficiente espacio en el Heap de objetos grandes, ejecuta el recopilador gen2, que está destruyendo el rendimiento. Aquí está el ejemplo simple que llamará constantemente a la colección gen2. Debe ejecutarlo en modo de depuración (debido a las optimizaciones del compilador).

static void Main(string[] args) 
{ 
    while (true) 
    { 
     byte[] objects = new byte[100000]; 
    } 
} 

¿Quiere decir esto que cada vez que necesito una matriz temporal cuyo tamaño es más grande que 85K, esa matriz va a terminar en la larget objetos del montón?

+0

Es posible que haya seguido adelante desde esta pregunta, solo un pensamiento mio al leer esto. Si pudieras usar estructuras en lugar de clases, esto reduciría en gran medida la presión del GC, ya que solo tendría que asignar toda la matriz como un bloque continuo de memoria y eliminarla como un bloque, solo haría una referencia a esa matriz como el los elementos en sí mismos son valores, no objetos. Después de eso, 'stackalloc' (en lugar de 'nuevo') podría ayudarlo a ubicarlo y liberarlo aún más rápido, aunque realmente tendría que hacerlo porque no es seguro. – gjvdkamp

2

En la primera generación0 puede aumentar y disminuir, pero esto es en el futuro. cuando el proceso se ejecuta, el almacenamiento gestionado inicializado tiene un tamaño fijo en generation0 256 KB (lo que significaba Richter) porque las computadoras modernas tienen 256 y más memoria para el efectivo de la CPU del segundo nivel. Segundo. Andrew, tienes razón. Cuando algún objeto es tan grande va a gen2 a la vez. Supongo que quería disminuir el tamaño de gen0 para provocar que se llame GC con más frecuencia para despejar el espacio no utilizado y mantener su aplicación más ligera. Tengo el mismo problema en un sitio web de SilverLight y busco una solución. Creo que si el código crea mucho objeto que tiene raíces y cuando gen0 está lleno, CLR llama a GC, que los mueve a gen1, y luego, cuando los objetos crecen, muévelos a gen2. Digamos que las 3 generaciones están casi llenas. Entonces, por ejemplo, GC llamó. Qué hará ¿Simplemente borrar generation0? ¿Cómo con 1-st y 2-nd. Creo que la solución para mantener la memoria liviana es la siguiente. Primero crea objetos pequeños y muchos en lugar de grandes y menos en conteo. Las referencias internas de los segundos objetos deben estar orientadas en una dirección y no en referencias caóticas entre sí. Los objetos estáticos que no se crean dinámicamente, por ejemplo, de acuerdo con los registros de la base de datos, deben mantenerse en las variables globales y no crear nuevamente cuando el código los califique.