2012-07-21 19 views
5

Tenemos algún tipo de fuga, cuya naturaleza no entiendo. Gen0/1/2 montones no aumentan de tamaño, sin embargo, el conjunto de trabajo aumenta hasta que OOM.Finalizer Queue crece pero Managed Heaps no

DebugDiag me dice que CLR.DLL posee la creciente memoria y también me dice que tenemos una creciente cola de finalizador - cientos de miles de objetos Texture2D (es una aplicación XNA) que aumentan con el tiempo ... Sin embargo, no hay perfilador (dotTrace , Ants, CLR Profiler) pueden encontrar estos objetos; no se muestran en el montón y CLRProfiler afirma que nunca se asignan.

Así que miro en WinDbg - una vez más puedo ver una creciente cola de Finalizer llena de Texture2D. fReachable está vacío y afirma que todos esos objetos están en el montón de todos modos.

*0:038> !finalizequeue 
SyncBlocks to be cleaned up: 0 
MTA Interfaces to be released: 0 
STA Interfaces to be released: 0 
---------------------------------- 
generation 0 has 1881 finalizable objects (33e365b0->33e38314) 
generation 1 has 41580 finalizable objects (33e0dc00->33e365b0) 
generation 2 has 685816 finalizable objects (33b70020->33e0dc00) 
Ready for finalization 0 objects (33e38314->33e38314) 
     MT Count TotalSize Class Name 
......snip...... 
00ce67e0 726827  49424236 Microsoft.Xna.Framework.Graphics.Texture2D* 

Entonces busque los 726.000 casos de modo que pueda encontrar quién es su propietario. El problema es que dumpheap dice que solo hay 218. Eso es más o menos lo que espero y lo que los perfiladores administrados me dicen que existe.

*0:038> !dumpheap -stat -type Microsoft.Xna.Framework.Graphics.Texture2D 
total 0 objects 
Statistics: 
     MT Count TotalSize Class Name 
00ce67e0  218  14824 Microsoft.Xna.Framework.Graphics.Texture2D 
Total 218 objects* 

Entonces, ¿de dónde viene el resto de los elementos en la cola del finalizador? En este momento, sospecho que la creciente cola del finalizador para las asignaciones de memoria a medida que crece y, por lo tanto, sale OOM. Es como si esos 218 elementos se agregaran a la cola del Finalizador varias veces por algún motivo.

Muchas gracias

Andy

no podía ser de la misma instancia que se está re-añadió
+0

Mencionas los gen0/1/2 montones, pero ¿y el montón de objetos grandes? ¿Es estable? ¿Qué quiere decir la gente en general con "tamaño de pila"? ¿Son los tamaños combinados de todos los objetos de ese montón, o el tamaño de la memoria reservada para el montón? Si la fragmentación es alta, estos dos valores pueden divergir. – Joh

+0

Sí, lo siento por no mencionar que el LOH también es muy estable, como lo es el contador de bytes en todos los montones. En general estoy hablando de los contadores perfmon para los tamaños. Cuando miré el diseño de la dirección del perfilador CLR, el LOH no está muy fragmentado y su tamaño general no está creciendo. Pero volveré y comprobaré eso. Gracias –

Respuesta

2

Para completar, esto es lo que estaba sucediendo.

Hay un problema con XNA que hace que se llame a ReRegisterForFinalize en Texture2Ds si tiene acceso a la colección Device.Texture []. Sunburn accede a esta colección en cada fotograma para resolver otro problema de XNA, por lo que si tiene muchas texturas, esto puede acumularse muy rápidamente.

Hay varios lugares en XNA (Texture3D, etc.) que usan el mismo patrón, así que supongo que puede reproducirlo de muchas maneras.

Como no hay signos de un XNA 5, tuvimos que evitarlo: descubrí que simplemente llamando a SuppressFInalize después de acceder a la colección elimina el elemento adicional que se había agregado. Creemos que es seguro :-) Los chicos de Sunburn están agregando una corrección en su código y esperamos que el problema desaparezca.

1

a la cola de finalización? De los documentos en Object.Finalize:

Finalize se llama automáticamente solo una vez en una instancia determinada, a menos que el objeto se vuelva a registrar utilizando un mecanismo como GC.ReRegisterForFinalize y GC.SuppressFinalize no se haya llamado posteriormente.

Esa es la única explicación que parece ajustarse a lo que está viendo aquí. Sin embargo, no estoy seguro de por qué sería re registrado para la finalización.

+0

Sí, podría ser. He recibido algunas sugerencias de que esta podría ser la causa. Sin embargo, ninguno de los códigos que tengo fuente utiliza GC.ReRegisterForFinalize, por lo que es difícil de depurar. Sé que la última versión del reflector .Net te permite puntos de interrupción en líneas de código dentro de binarios, así que podría intentarlo. Mi vudú WinDbg no es lo suficientemente fuerte como para hacerlo de la manera difícil. –