2009-08-12 9 views
6

Tengo una aplicación de WindowsForms que parece perder memoria, así que utilicé ANTS Memory Profiler de Redgate para mirar los objetos que sospecho y descubrí que solo los tienen los objetos que ya están en el Finalizer Queue. Genial, ¿qué es exactamente la cola de finalizadores? ¿Puedes señalarme la mejor definición? ¿Puedes compartir algún consejo anecdótico?¿Cuáles son los Finalizer Queue y Control + ThreadMethodEntry?

Además, todos los objetos raíz de GC en la cola de finalizador son instancias de System.Windows.Forms.Control + ThreadMethodEntry objetos denominados "llamador". Veo que está involucrado en la interacción de UI de múltiples hilos, pero no sé mucho más que eso. Perdona mi aparente flojera y admitido mi ignorancia, pero estos recursos están enterrados dentro del componente de un proveedor. Estoy hablando con el proveedor sobre estos problemas, pero necesito alguna dirección para ponerme al día con la conversación. ¿Puede indicarme la definición más útil de ThreadMethodEntry también? ¿Algún consejo anecdótico?

Además, ¿debería preocuparme por estos objetos en la cola del finalizador?

Actualización: Este Red Gate article fue útil.

Respuesta

14

La cola del finalizador contiene todos los objetos que tienen un método de finalizador definido. Recuerde que un finalizador es un medio para recopilar recursos no administrados como identificadores. Cuando el recolector de basura recoge basura, mueve cualquier objeto con un finalizador a la cola del finalizador. En algún momento posterior, dependiendo de la presión de la memoria, la heurística del GC y la fase de la luna, cuando el recolector de basura decide recoger estos objetos, recorre la cola y ejecuta los finalizadores.

Después de haber trabajado con fugas de memoria en el pasado, ver un montón de objetos de su proveedor en la cola del finalizador podría ser un código descuidado, pero no indica una pérdida de memoria. Normalmente, un buen código expondrá un método de eliminación que recopilará recursos administrados y no administrados, y al hacerlo, se eliminará de la cola del finalizador a través del GC.SuppressFinalize(). Entonces, si los objetos del proveedor implementan un método Dispose y su código no lo llama, eso podría generar un grupo de objetos en la cola del finalizador.

¿Ha intentado crear una instantánea en ANTS entre dos puntos en el tiempo y comparar los objetos creados entre ellos? Eso puede ayudarlo a identificar cualquier objeto administrado que se filtre.

Además, si usted quiere ver si la memoria desaparece cuando se ejecutan los finalizadores, probar esto sólo para probar con:

 
System.GC.Collect(); 
System.GC.WaitForPendingFinalizers(); // this method may block while it runs the finalizers 
System.GC.Collect(); 

No recomiendo ejecutar este código normalmente. Es posible que desee ejecutarlo si acaba de hacer un montón de trabajo y ha creado gran cantidad de basura. Por ejemplo, en nuestra aplicación, una de nuestras funciones puede crear aproximadamente 350 MB de basura que se desperdicia después de cerrar una ventana MDI. Como se sabe que esto deja mucha basura, forzamos manualmente la recolección de basura.

También tenga en cuenta que hay un caché de propiedades de bajo nivel en el código base de Windows.Forms que se aferrará al último cuadro de diálogo modal abierto. Esto podría ser una fuente de pérdida de memoria. Una forma segura de deshacerse de esta referencia es forzar a que aparezca otro cuadro de diálogo simple, luego ejecutar el código de GC anterior.

+0

Gracias por la gran respuesta, Paul. Ese es el gráfico de referencia del objeto del que estoy hablando, mirando los objetos nuevos en la segunda instantánea, después de que los recursos se limpien. Todos los objetos en el gráfico que implementan IDisposable tienen una información sobre herramientas que dice "Se ha llamado a Dispose() para este objeto", pero el objeto seleccionado no tiene dicha información sobre herramientas. – flipdoubt

+2

Nota sobre ThreadMethodEntry: creo que se usan en cualquier invocación al subproceso de interfaz de usuario. Cada objeto Control tiene una cola de devolución de llamadas de tipo ThreadMethodEntry. Una devolución de llamada dequeues ThreadMethodEntry y lo ejecuta. Cada objeto ThreadMethodEntry tiene varios campos internos. El examen de estos campos puede ayudarlo a determinar cuáles de los objetos de este proveedor están invocando. No recuerdo si puede obtener esa información de ANTS, pero sé que puede hacerlo a través de WinDbg.dll y sos.dll (extensiones del depurador gestionado). Mire el delegado "método" y el control "llamador". –

+0

Además, tenga en cuenta que los objetos ThreadMethodEntry implementan un finalizador, pero no tienen un método Dispose. Cuando completen, también se moverán a la cola del finalizador. –

1

La cola del finalizador es una cola donde las instancias de objetos que ya no se utilizan esperan a ser finalizadas por el GC. Todos los objetos en esta cola se finalizarán y su memoria se filtra probablemente no provenga de uno de estos directamente. Pero, uno de estos objetos puede no lanzar todos sus recursos no administrados.

La clase ThreadMethodEntry es una implementación de IAsyncResult y las instancias de esta clase se crean normalmente al invocar operaciones asincrónicas, como usar Invoke para actualizar la interfaz de usuario o utilizar los métodos Begin */End *.

0

Here's una buena publicación de blog que describe un problema similar. En un nivel más técnico, podría utilizar SOS.dll (que describe la publicación del blog) y Sosex.dll para ayudarlo a averiguar por qué estos objetos ThreadMethodEntry se quedan en la memoria. Hay comandos en estas extensiones WinDbg que pueden rastrear qué otros objetos están haciendo referencia a un objeto específico en la memoria.

Cuestiones relacionadas