2012-06-21 13 views
7

Estoy trabajando en una aplicación .NET donde parece haber una pérdida de memoria. Sé que las respuestas de libros de texto, que los eventos deben ser no suscritas, objetos desechables deben ser eliminados, etc ...Depuración de fugas de memoria .NET: cómo saber qué contiene una referencia a qué?

que tienen un arnés de prueba que puede reproducir el error. En el finalizador de cierta clase escribo a la consola

public class Foo 
{ 
    // Ctor 
    public Foo() 
    { 
    } 

    ~public Foo() 
    { 
     Console.WriteLine("Foo Finalized"); 
    } 
} 

en el instrumento de prueba, estoy creando una única instancia de Foo (que a su vez crea e interactúa con cientos de otros tipos) luego se retire e invocando el Recolector de basura.

estoy encontrando la Foo Finalizer nunca es llamado. Tengo una clase similar con esta configuración que se finaliza como una prueba de control.

Así que mi pregunta es la siguiente:

¿Cómo puedo determinar el uso de herramientas comerciales o de código abierto exactamente lo está sosteniendo una referencia a Foo?

Tengo una licencia profesional para dotTrace Memory profiler pero no puedo entender de los archivos de ayuda cómo usarlo.

Actualización: Ahora estoy usando dotMemory 4.0, que es el sucesor de la (buena, pero inutilizable) dotTrace Memory 3.5.

+1

si ya tiene un profiler, aprenda a usarlo - No trabajé mucho con dotTrace, pero los otros dos son similares en los patrones de uso y necesito algo de "get into" también – Carsten

+0

@ CarstenKönig +1 a esto, Estoy cavando en dotTrace ahora. Me imagino que puedo encontrar una lista de objetos no recolectados por espacio de nombres (así encontré mi Foo ofensivo) y lo que contiene una referencia a ellos, nuevamente filtrada por espacio de nombres (cientos), ahora revisando una lista de manejadores de eventos sospechosos, etc ... –

+0

@ CarstenKönig De hecho, lo encontró usando dotTrace! Tiene la función de profundizar en el gráfico de gcroot -> Foo, un poco difícil de encontrar. Saludos :) –

Respuesta

3

El finalizador no se llama de forma determinista, así que ten cuidado de utilizarlo para realizar un seguimiento de las cosas de una manera fiable. Si elimina el finalizador y, en su lugar, usa un WeakReference<Foo>, debe poder determinar si el objeto fue recolectado.

Todos los perfiladores de memoria deben ser capaces de encontrar un tema como este, pero con diferentes grados de dificultad. Personalmente he usado ANTS, que es muy fácil de usar, pero no gratis. Le ayudará a mostrar un diagrama de referencia a la instancia de Foo, todo el camino desde un objeto raíz de GC. Al ver este diagrama, generalmente es fácil identificar quién está llevando a cabo la referencia.

2

Puede utilizar perfiladores de memoria para identificar las pérdidas de memoria. Éstos son algunos,

MemProfiler

ANTS Profiler

+0

Votado para ANTS Profiler. En una aplicación empresarial razonablemente grande, logró encontrar una gran pérdida de recursos que había escapado de la detección durante 3 años. – Contango

6

Tiene un look en la extensión SOS debugger (es gratis, y se puede usar en Visual Studio).

Puede encontrar this y this útiles para iniciarse.

Si ha establecido con éxito et arriba SOS (esto puede ser difícil a veces), a sabiendas de lo que contiene una referencia a lo que es tan fácil como

// load sos 
.load sos 
// list of all instances of YourTypeName in memory with their method tables 
!DumpHeap -type YourTypeName 
// put here the method table displayed by the previous command 
// it will show you the memory address of the object 
!DumpHeap -mt 07f66b44    
// displays information about references the object at the specified address 
!GCRoot 02d6ec94 
+0

Gracias por esto, definitivamente voy a intentarlo. Sería bueno si hubiera un buen tutorial sobre dotTrace pero lamentablemente no! –

1

En primer lugar no se debe utilizar un finalizador, porque:

operaciones Finalizar tienen las siguientes limitaciones:

  • el momento exacto cuando el finalizador se ejecutan durante la basura la colección no está definida. No se garantiza que los recursos se liberen en cualquier momento específico de , a menos que se llame a un método Cerrar o a un método Eliminar.

  • No se garantiza que los finalizadores de dos objetos se ejecuten en ningún orden específico , incluso si un objeto hace referencia al otro. Es decir, si El objeto A tiene una referencia al Objeto B y ambos tienen finalizadores, el Objeto B podría haber finalizado cuando se inicia el finalizador del Objeto A.

  • El subproceso en el que se ejecuta el finalizador no está especificado.

Cita de: http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx
se recomienda usar método Dispose en su lugar.

En segundo lugar, cualquier generador de perfiles de memoria debería poder encontrar lo que contiene esas referencias. Personalmente, estaba usando ANTS Profiler, es una herramienta muy buena y tiene una documentación bastante rica. Puede intentar leer este documento: http://downloads.red-gate.com/HelpPDF/ANTS_Memory_Profiler/InstanceCategorizer.pdf El categorizador de instancias muestra cadenas de referencias de conjuntos de objetos a la raíz de la GC.

+0

Aunque tiene toda la razón, en algunos casos es realmente necesario utilizar Finalizer. Considere que creó un control personalizado para representar superficies 3D que redistribuye a los usuarios finales. Es poco probable que los usuarios finales llamen .Dispose() a su control una vez que ya no esté en uso. Esperan que 'solo funcione'. Además, la basura de WPF recolecta vistas cuando están modeladas y en un control de pestañas, y están tabuladas y pulg. En estos casos es imposible llamar. Deshacer y el Finalizador es la mejor opción para liberar recursos no administrados llamando directamente a Dispose, si no todavía –

6

Las fugas de memoria de depuración pueden ser un proceso bastante complicado y requieren una comprensión exhaustiva de la lógica de su programa y al menos algunos internos de .Net (especialmente el comportamiento del recolector de basura).

Para más información consultar los siguientes enlaces:

buena introducción

curso práctico:

GC y.internos netos

WinDBG con extensión SOS

buena suerte!

Cuestiones relacionadas