2009-09-24 13 views
15

Tengo un objeto, que vive para siempre. Estoy borrando todas las referencias que puedo ver, después de usarlo, pero aún no recogido. Su ciclo de vida es bastante sofisticado, así que no puedo estar seguro de que se hayan borrado todas las referencias.Buscar referencias al objeto en tiempo de ejecución

if (container.Controls.Count > 0) 
{ 
    var controls = new Control[ container.Controls.Count ]; 
    container.Controls.CopyTo(controls, 0); 

    foreach (var control in controls) 
    { 
     container.Controls.Remove(control); 
     control.Dispose(); 
    } 

    controls = null; 
} 

GC.Collect(); 
GC.Collect(1); 
GC.Collect(2); 
GC.Collect(3); 

¿Cómo puedo averiguar qué referencias ¿todavía tiene? ¿Por qué no se recoge?

+0

Muéstranos tu código y es posible que podamos ayudarte. Tenga en cuenta que la recolección de basura no necesariamente ocurre inmediatamente. – Lazarus

+0

Y creo que la verdadera pregunta es, ¿por qué te preocupas? Si está utilizando recursos Desechables, elimínelos cuando ya no los esté usando, limpie los recursos del sistema no administrados y tenga cuidado con el interrogatorio de cadenas. –

+0

El código es: si (container.Controls.Count> 0) { \t \t \t \t controles var = nuevo Control [container.Controls.Count]; \t \t \t \t container.Controls.CopyTo (controles, 0); \t \t \t \t foreach (control var en los controles) { \t \t \t \t \t container.Controls.Remove (control); \t \t \t \t \t control.Disponer(); \t \t \t \t \t \t \t \t \t} \t \t \t \t controles = NULL; \t \t \t} GC.Collect(); GC.Collection (1); GC.Collection (2); GC.Collection (3); Pero todavía está en la memoria. Entonces, es que el acero tiene raíces. ¿Cómo puedo encontrar estas raíces? –

Respuesta

11

Pruebe usar perfilador de memoria, (por ejemplo, ants) le dirá qué es lo que mantiene vivo el objeto. Intentar adivinar por segunda vez este tipo de problema es muy difícil.

Red-gate ofrece 14 días de prueba que deberían ser más que suficientes para solucionar este problema y decidir si un generador de perfiles de memoria le proporciona un valor a largo plazo.

Hay un montón de otros perfiladores de memoria en el mercado (por ejemplo .NET Memory Profiler) la mayor parte de ellos tienen pruebas gratuitas, sin embargo he encontrado que los Red-Gate herramientas son fáciles de usar, por lo que tienden probarlos primero.

+0

¡Gracias, lo intentaré! –

+0

También tienen algunos videos (y documentos) de capacitación gratuitos que explican cómo funciona el recolector de basura .net que puede serle útil. –

+0

@ er-v: es posible que se haya recopilado su objeto, pero la memoria puede no haber sido recuperada por Windows. El marco no tiene que devolver memoria al sistema operativo. – user7116

0

No se recoge porque no ha eliminado todas las referencias. El GC solo marcará objetos para colección si no tienen raíces en la aplicación.

¿Qué medios usa para verificar en el GC para ver si ha recogido su objeto?

2

La recolección de basura en .NET no es un esquema de conteo (como COM), sino una implementación de marcado y barrido. Básicamente, el GC se ejecuta en momentos "aleatorios" cuando siente la necesidad de hacerlo, y la colección de los objetos no es determinista.

Puede, sin embargo, activar manualmente una colección (GC.Collect()), pero es posible que tenga que esperar a que se ejecuten los finalizadores (GC.WaitForPendingFinalizers()). Sin embargo, se desaconseja hacer esto en una aplicación de producción, ya que puede afectar la eficiencia de la gestión de la memoria (el GC se ejecuta con demasiada frecuencia o espera que se ejecuten los finalizadores). Si el objeto aún existe, en realidad todavía tiene alguna referencia en vivo en alguna parte.

3

Tendrás que usar la extensión Windbg y Sosex.

Los comandos !DumpHeap y !GCRoot pueden ayudarlo a identificar la instancia y todas las referencias restantes que la mantienen activa.

3

He estado usando .NET Memory Profiler para hacer algunos perfiles de memoria serios en uno de nuestros proyectos. Es una gran herramienta para analizar la administración de la memoria de su aplicación. No me pagan por esta información :) pero me ayudó mucho.

+0

De acuerdo, es una herramienta muy útil, especialmente las cosas visuales. –

3

Resolví un problema similar con la extensión SOS (que aparentemente ya no funciona con Visual Studio 2013, pero funciona bien con las versiones anteriores de Visual Studio).

utilicé siguiente código para obtener la dirección del objeto para el que quería realizar un seguimiento de las referencias:

public static string GetAddress(object o) 
{ 
    if (o == null) 
    { 
     return "00000000"; 
    } 
    else 
    { 
     unsafe 
     { 
      System.TypedReference tr = __makeref(o); 
      System.IntPtr ptr = **(System.IntPtr**) (&tr); 
      return ptr.ToString ("X"); 
     } 
    } 
} 

y luego, en Visual Studio 2012 ventana inmediata, mientras se ejecuta en el depurador, escriba:

.load C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll 

que cargará la extensión SOS.dll.

A continuación, puede utilizar GetAddress(x) para obtener la dirección hexadecimal del objeto (por ejemplo 8AB0CD40), y luego usar:

!do 8AB0CD40 
!GCRoot -all 8AB0CD40 

para volcar el objeto y encontrar todas las referencias al objeto.

Solo tenga en cuenta que si el GC se ejecuta, podría cambiar la dirección del objeto.

Cuestiones relacionadas