Pregunta

¿Cuáles son todas las formas posibles en las que podemos sufrir pérdidas de memoria en .NET?

Conozco dos:

  1. No darse de baja correctamente Controladores/delegados de eventos.
  2. No eliminar controles secundarios dinámicos en Windows Forms:

Ejemplo:

// Causes Leaks  
Label label = new Label();  
this.Controls.Add(label);  
this.Controls.Remove(label);  

// Correct Code  
Label label = new Label();  
this.Controls.Add(label);  
this.Controls.Remove(label);  
label.Dispose();

Actualizar:La idea es enumerar errores comunes que no son demasiado obvios (como los anteriores).Por lo general, la idea es que las pérdidas de memoria no son un gran problema debido al recolector de basura.No como solía ser en C++.


Gran discusión chicos, pero déjenme aclarar...por definición, si no queda ninguna referencia a un objeto en .NET, en algún momento se recolectará basura.Entonces esa no es una forma de inducir pérdidas de memoria.

En el entorno administrado, lo consideraría una pérdida de memoria si tuviera una referencia no deseada a cualquier objeto que no conoce (de ahí los dos ejemplos en mi pregunta).

Entonces, ¿cuáles son las diversas formas posibles en que puede ocurrir tal pérdida de memoria?

¿Fue útil?

Solución

Bloquea el hilo finalizador.Ningún otro objeto será recolectado como basura hasta que se desbloquee el subproceso finalizador.Por lo tanto, la cantidad de memoria utilizada crecerá y crecerá.

Otras lecturas: http://dotnetdebug.net/2005/06/22/blocked-finalizer-thread/

Otros consejos

Eso realmente no causa fugas, simplemente hace que el GC trabaje más:

// slows GC
Label label = new Label();  
this.Controls.Add(label);  
this.Controls.Remove(label);  

// better  
Label label = new Label();  
this.Controls.Add(label);  
this.Controls.Remove(label);  
label.Dispose();

// best
using( Label label = new Label() )
{ 
    this.Controls.Add(label);  
    this.Controls.Remove(label);  
}

Dejar componentes desechables tirados así nunca es un gran problema en un entorno administrado como .Net; eso es una gran parte de lo que significa administrado.

Sin duda, ralentizarás tu aplicación.Pero no dejarás un desastre para nada más.

Configurando el GridControl.Fuente de datos propiedad directamente sin utilizar una instancia de la clase BindingSource (http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.aspx).

Esto provocó fugas en mi aplicación que me llevó bastante tiempo localizar con un generador de perfiles; finalmente encontré este informe de error al que Microsoft respondió: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=92260

Es curioso que en la documentación de la clase BindingSource Microsoft intente hacerla pasar como una clase legítima y bien pensada, pero creo que simplemente la crearon para resolver una fuga fundamental relacionada con los administradores de divisas y la vinculación de datos a los controles de la red.

¡Cuidado con esto, apuesto a que hay muchísimas aplicaciones con fugas debido a esto!

No hay forma de proporcionar una lista completa...Esto es muy parecido a preguntar "¿Cómo puedes mojarte?"

Dicho esto, asegúrese de llamar a Dispose() en todo lo que implemente IDisposable y asegúrese de implementar IDisposable en cualquier tipo que consuma recursos no administrados de cualquier tipo.

De vez en cuando, ejecute algo como FxCop en su código base para ayudarle a hacer cumplir esa regla; se sorprenderá de cuán profundamente quedan enterrados algunos objetos desechables dentro del marco de una aplicación.

Excepciones en los métodos Finalize (o Dispose de un Finalizer) que impiden que los recursos no administrados se eliminen correctamente.Uno común se debe al programador. asumiendo en qué orden se eliminarán los objetos y al intentar liberar objetos pares que ya se han eliminado, lo que resulta en una excepción y no se llama al resto del método Finalizar/Disponer de Finalizar.

Tengo 4 elementos adicionales para agregar a esta discusión:

  1. Terminar subprocesos (Thread.Abort()) que han creado controles de interfaz de usuario sin prepararse adecuadamente para tal evento puede provocar que la memoria se use de manera expectante.

  2. Acceder a recursos no administrados a través de Pinvoke y no limpiarlos puede provocar pérdidas de memoria.

  3. Modificación de objetos de cadena grandes.No necesariamente es una pérdida de memoria; una vez fuera del alcance, GC se encargará de ello; sin embargo, en cuanto al rendimiento, su sistema puede verse afectado si las cadenas grandes se modifican con frecuencia porque realmente no puede depender de GC para garantizar que la huella de su programa sea correcta. mínimo.

  4. Crear objetos GDI con frecuencia para realizar dibujos personalizados.Si realiza trabajos GDI con frecuencia, reutilice un único objeto gdi.

Llamar a IDisposable cada vez es el lugar más fácil para comenzar y, definitivamente, una forma efectiva de aprovechar todas las pérdidas de memoria en el código base.Sin embargo, no siempre es suficiente.Por ejemplo, también es importante comprender cómo y cuándo se genera el código administrado en tiempo de ejecución y que una vez que los ensamblados se cargan en el dominio de la aplicación, nunca se descargan, lo que puede aumentar el espacio de la aplicación.

Para evitar pérdidas de memoria .NET:

1) Emplee la construcción 'usando' (o 'construcción de prueba final') siempre que se cree un objeto con una interfaz 'IDisposable'.

2) Haga que las clases sean 'IDisposables' si crean un hilo o agregan un objeto a una colección estática o de larga duración.Recuerde que un 'evento' de C# es una colección.

Aquí hay un breve artículo sobre Consejos para prevenir pérdidas de memoria.

¿Estás hablando de un uso inesperado de la memoria o de fugas reales?Los dos casos que enumeró no son exactamente fugas;son casos en los que los objetos permanecen más tiempo del previsto.

En otras palabras, son referencias que quien las llama pérdidas de memoria no conocía o olvidó.

Editar:O son errores reales en el recolector de basura o código no administrado.

Edición 2:Otra forma de pensar en esto es asegurarse siempre de que las referencias externas a sus objetos se publiquen de manera adecuada.Externo significa código fuera de su control.Cualquier caso en el que eso suceda es un caso en el que se puede "perder" memoria.

  1. Mantener referencias a objetos que ya no necesita.

Con respecto a otros comentarios: una forma de garantizar que se llame a Dispose es usar usando...cuando la estructura del código lo permite.

Una cosa que fue realmente inesperada para mí es esta:

Region oldClip = graphics.Clip;
using (Region newClip = new Region(...))
{
    graphics.Clip = newClip;
    // draw something
    graphics.Clip = oldClip;
}

¿Dónde está la pérdida de memoria?Bien, deberías haberte deshecho oldClip, ¡también!Porque Graphics.Clip es una de las raras propiedades que devuelve un nuevo objeto desechable cada vez que se invoca el captador.

Tess Fernandez tiene excelentes publicaciones en su blog sobre cómo encontrar y depurar pérdidas de memoria.laboratorio 6 laboratorio 7

Muchas de las cosas que pueden causar pérdidas de memoria en lenguajes no administrados aún pueden causar pérdidas de memoria en lenguajes administrados.Por ejemplo, malas políticas de almacenamiento en caché puede provocar pérdidas de memoria.

Pero como han dicho Greg y Danny, no existe una lista completa.Cualquier cosa que pueda provocar que la memoria se retenga después de su vida útil puede provocar una fuga.

Los hilos estancados nunca liberarán raíces.Obviamente se podría argumentar que el estancamiento presenta un problema mayor.

Un subproceso finalizador bloqueado impedirá que se ejecuten todos los finalizadores restantes y, por lo tanto, evitará que se recuperen todos los objetos finalizables (ya que todavía están siendo rooteados por la lista accesible).

En una máquina con múltiples CPU, podría crear objetos finalizables más rápido de lo que el subproceso del finalizador podría ejecutar los finalizadores.Mientras eso se mantenga, se "perderá" memoria.Probablemente no sea muy probable que esto suceda en la naturaleza, pero es fácil de reproducir.

El montón de objetos grandes no está compactado, por lo que podría perder memoria mediante la fragmentación.

Hay una serie de objetos que deben liberarse manualmente.P.ej.objetos remotos sin arrendamiento y ensamblajes (debe descargar AppDomain).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top