2011-08-03 24 views
11

Tengo un Winform blanco con un método destructor¿Por qué mi destructor nunca se ejecuta?

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     System.Diagnostics.Trace.WriteLine("Form1.Initialize " + this.GetHashCode().ToString()); 
     InitializeComponent(); 
    } 
    ~Form1() 
    { 
     System.Diagnostics.Trace.WriteLine("Form1.Dispose " + this.GetHashCode().ToString()); 
    } 
} 

Cuando el formulario se destruye, quiero que pueda escribir en la ventana de salida:

 
(Form1 opened) 
Form1.Initialize 41149443 
(Form1 closed) 
Form1.Dispose 41149443 

MSDN sugiere 3 maneras en destructor de aplicación:

Sin embargo, ninguna de estas formas de escribir "Form1.Dispose 41149443" a la ventana de salida. Por lo tanto, no puedo decir si el formulario se ha destruido o no. Sugerencias?

¿Debo renunciar a la esperanza de lograr esto debido a la incertidumbre del recolector de basura?

¿Hay otra manera de saber si Form1 ha sido recogido de basura?

+0

¿Por qué? ¿Que estás tratando de hacer? – SLaks

+0

No puede suponer que se va a llamar al destructor. (Por ejemplo, si tiene suficiente memoria, es perfectamente válido nunca llamar a ningún destructor, nunca). – katrielalex

+0

¿No está escrito el rastro? –

Respuesta

9

Solo una de las tres formas de implementar un destructor que lista realmente involucra un destructor, y es ~Destructor().

Si implementa IDisposable y se deshace de su objeto, se ejecutará el código en Dispose, pero no hay motivo para pensar que su destructor lo hará.

creo que te persiguen lo imposible aquí. Destructores ejecutan como y cuando el recolector de basura lo decreta. No es algo sobre lo que tengas control. El GC está en su derecho de formar la opinión de que ejecutar destructores simplemente desperdicia tiempo, y si hay mucha memoria formará esa opinión.

Si necesita eliminación, finalización, etc. predecibles, utilice IDisposable.

+0

IDisposable no es automáticamente predecible, debe llamar a Dispose o usar usando(). ¿Y cómo llamarías a Dispose()? – slfan

+1

@slfan ¿De qué estás hablando? 'Dispose' se ejecuta cuando se llama, invariablemente a través de' using'. ¿Dónde dije que 'Dispose' se ejecutará automáticamente? –

+0

Usted escribió "si necesita una eliminación predecible ...". Si no usa o lo llama explícitamente, no se llama. Como nunca he usado con un formulario, es incluso menos predecible que el finalizador. – slfan

1

Sí, probablemente debería renunciar a la idea de un destructor, porque no son deterministas por naturaleza. No estoy seguro de por qué es necesario tener la forma dispuesta en lugar de sólo cerrado, sino simplemente cerrando debería ser suficiente en la mayoría de los casos.

Puede usar IDisposable pero eso depende de por qué necesita que el formulario sea basura. Si necesita volver a usarlo, simplemente cree otra instancia.

1

El formulario obtiene la basura recogida cuando no hay referencias y se ejecuta el recolector de elementos no utilizados. Puede forzar al recolector de basura llamando a GC.Collect(). No debe hacer referencia a ningún otro objeto dentro de un Finalizer (también conocido como destructor) porque el objeto ya puede haber sido recogido.

Puede utilizar las herramientas del analizador de memoria para averiguar si su objeto es basura o no, si es que realmente lo necesita.

También debe tener en cuenta que el finalizador se llama desde un hilo que no sea el hilo principal.

EDIT: Si su problema es simplemente que no ve la salida de rastreo, puede que tenga que girar autoflush en

<configuration> 
    <system.diagnostics> 
    <trace autoflush="true" /> 
    </system.diagnostics> 
</configuration> 

EDIT 2: Puede haber una referencia externa a su forma, como un controlador de eventos registrado. Yo sugeriría que se agrega un botón en un área de administración de la aplicación que se ejecuta el siguiente código:

GC.Collect(); 
GC.WaitForPendingFinalizers(); 
GC.Collect(); 

gusta esta el recolector de basura debe correr y debería destruir su forma (establecer un punto de interrupción en el finalizador). Si no, tiene alguna referencia al objeto que debe destruirse.

+0

Sí, el autoflush aún no resuelve el problema. –

+0

Ok, prueba mi 2ª conjetura. Tal vez tengas algunas referencias al formulario. – slfan

+0

Probé la segunda opción y funcionó. Creo que la tuya es la respuesta más cercana en comparación con otras. –

4

A menos que esté estudiando la recolección de basura, un destructor no es el lugar para su rastreo. Deberías mirar Dispose (que es anulable en Form). Esto ocurre después de que se haya liberado el recurso no administrado (como su identificador de ventana).

protected override void Dispose(bool disposing) 
{ 
    System.Diagnostics.Trace.WriteLine(
     "Form1.Dispose " + (disposing ? "disposing " : "") 
     + this.GetHashCode().ToString()); 
    base.Dispose (disposing); 
} 

Si usted quiere ver si un formulario/control se ha eliminado, utilice la propiedad Control.IsDisposed.

Editar: Debido a GC.SuppressFinalize, su método Finalize (sintaxis del destructor en C#) nunca se ejecutará si se llama a Dispose explícitamente (o por el framework).

Para obtener más información, consulte Implementing a Dispose Method.

+0

@ agent-j no debería ser '' Form1.Dispose "+ (¿Desechar?" Disponer de ":" ")' – apacay

+0

@apacay, gracias. arreglado –

+0

@slfan, mi punto es que esto es llamado por el finalizador solo si es necesario. Si alguien dispone el formulario explícitamente, el destructor (método de finalización) probablemente nunca se ejecutará debido a GC.SupressFinalize. Ver el patrón Dispose para más información. –

0

Puede intentar envolver su formulario en un objeto WeakReference y luego verificar su propiedad IsAlive para determinar si se ha recogido basura. Pero, sí ... según las otras respuestas, es mejor que lo dejes y confíes en que el GC hará su trabajo.

1

Agregue un evento FormClosed al diseñador.

es decir:

this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(Form1_FormClosed); 

Entonces crear la función apropiada para controlar el evento.

Cuestiones relacionadas