7

Tenemos una aplicación de Windows Forms que contiene miles de formularios.Usando una declaración en el formulario de diálogo para asegurar la recolección de basura

Muchos de estos se muestran temporalmente como cuadros de diálogo mediante el método ShowDialog().

Esta aplicación existe desde hace años y descubrimos que muchos de los formularios no reciben basura recolectada de manera oportuna debido a varias filtraciones de recursos en la forma o los controles que utiliza.

Específicamente, hemos encontrado ejemplos de recursos de GDI + que no se eliminan correctamente, aunque puede haber otros tipos de pérdidas de recursos que aún no se han caracterizado.

Aunque la forma correcta de resolver esto es, obviamente, pasar por cada forma y cada control y eliminar todos los problemas de recursos. Esto tomará un tiempo para lograrlo.

Como una alternativa a corto plazo, hemos encontrado que llamar explícitamente a Dispose() en el formulario parece iniciar el proceso de recolección de basura y la forma y sus recursos se desasignan inmediatamente.

Mi pregunta es si sería una solución razonable para envolver el bloque ShowDialog() de cada formulario en una declaración using para que se llame a Dispose() después de que se haya mostrado el formulario, y también sería una buena práctica instituir ¿en general?

Por ejemplo, cambie el código existente de esto:

public void ShowMyForm() 
{ 
    MyForm myForm = new MyForm(); 
    myForm.ShowDialog(); 
} 

A esto:

public void ShowMyForm() 
{ 
    using (MyForm myForm = new MyForm()) 
    { 
     myForm.ShowDialog(); 
    } 
} 

En nuestras pruebas, a disponer de MiFormulario() método nunca se llamó para el primer ejemplo, pero se llama inmediatamente para el segundo ejemplo.

¿Esto parece un enfoque razonable como una solución a corto plazo mientras pasamos el tiempo rastreando cada uno de los problemas de recursos específicos?

¿Existen otros enfoques que podríamos considerar para una solución a corto plazo y/o metodologías para identificar y resolver este tipo de problemas de recursos?

+0

Sí, esta es la mejor práctica para los diálogos de uso y descarte. Además, Dispose solo se invocará si lo llamas explícitamente (como mediante 'using'), por lo que si tienes recursos no administrados, es posible que necesites implementar un finalizador o usar clases de contenedor como varios derivados de SafeHandle para asegurarte de que los recursos estén limpiado incluso si no se llama Dispose. –

+1

Tenga en cuenta que hay una gran diferencia entre Dispose() y GC. Eliminar es lo correcto que hay que hacer aquí, y liberará los recursos no administrados, pero no es GC. –

+0

Nota: el uso de 'Controls.Clear();' puede causar una pérdida de memoria. Vea el comentario de Hans aquí http://stackoverflow.com/a/7706549/939213. – ispiro

Respuesta

11

Según MSDN, debe llamar explícitamente a Dispose en formas mostradas usando ShowDialog (al contrario que con el método Show):

Cuando un formulario se muestra como un cuadro de diálogo modal, haga clic en el botón Cerrar (la botón con una X en la esquina superior derecha del formulario) hace que el formulario se oculte y la propiedad DialogResult se establezca en DialogResult.Cancel. A diferencia de los formularios no modales, el método Close es no llamado por .NET Framework cuando el usuario hace clic en el botón Cerrar formulario de un cuadro de diálogo o establece el valor de la propiedad DialogResult. En su lugar, el formulario está oculto y se puede volver a mostrar sin crear una nueva instancia del cuadro de diálogo. Como un formulario mostrado como cuadro de diálogo está oculto en lugar de cerrado, debe llamar al método Dispose del cuando la aplicación ya no necesita el formulario.

+0

Esto fue muy interesante de aprender, especialmente porque aparece en el texto de ayuda del método Form.ShowDialog: http://msdn.microsoft.com/en-us/library/c7ykbedk.aspx – Avalanchis

+0

Si no se llama a Dispose ShowDialog, pero no hay filtraciones de recursos en el formulario, ¿se eliminará finalmente de todos modos (antes de que termine la aplicación)? – Avalanchis

1

En general, es una buena forma de utilizar la declaración using para objetos que implementan IDisposable.

Una pequeña muestra de la situación:

Digamos que tiene un tercero "componente". No puede saber internamente y quizás este objeto cree un archivo temporal y elimine el archivo en Dispose. Si no llama al Dispose() y no usa using, el archivo nunca será borrado.

En su caso, puede hacerlo también siempre y cuando abra su formulario modal.

2

Para cuadros de diálogo modales, se debe utilizar el patrón:

using (var dlg = new MyDialog()) 
{ 
    // other code here to initialize, etc. 
    dlg.ShowDialog(); 
} 

Desde MyDialog se deriva de Formulario, y el Formulario implementa IDisposable , este patrón correctamente la limpieza de su diálogo.

Esto no debe ser una "solución temporal a corto plazo", sino la forma estándar en que debe invocar todos sus cuadros de diálogo modales.

Los diálogos sin modo son otra historia. Tendrá que hacer un seguimiento de ellos usted mismo, y llame al Deseche en los puntos apropiados en su aplicación.

Cuestiones relacionadas