Anatomía de una " Fuga de memoria"


En perspectiva. NET:

  • ¿Qué es una fuga de memoria ?
  • ¿Cómo puede determinar si su aplicación se filtra? ¿Cuáles son los efectos?
  • ¿Cómo se puede prevenir una fuga de memoria?
  • Si su aplicación tiene una fuga de memoria, ¿desaparece cuando el proceso sale o muere? ¿O las fugas de memoria en su aplicación afectan a otros procesos en el sistema incluso después de la finalización del proceso?
  • Y qué pasa con el código no administrado accedido a través de COM Interop y / o P / Invocar?
Author: Zoe, 2008-08-01

15 answers

La mejor explicación que he visto está en el Capítulo 7 del libro electrónico gratuito Fundamentos de la Programación.

Básicamente, en . NET se produce una fuga de memoria cuando los objetos referenciados están arraigados y, por lo tanto, no se pueden recolectar basura. Esto ocurre accidentalmente cuando se aferra a referencias más allá del alcance previsto.

Sabrás que tienes fugas cuando empieces a salir de las excepciones de Memoryexceptions o tu uso de memoria va más allá de lo que esperarías (PerfMon tiene un buen contadores de memoria).

Comprender el modelo de memoria de . NET es la mejor manera de evitarlo. Específicamente, entender cómo funciona el recolector de basura y cómo funcionan las referencias-de nuevo, lo remito al capítulo 7 del libro electrónico. Además, tenga en cuenta las trampas comunes, probablemente las más comunes sean los eventos. Si object A está registrado en un evento en object B, entonces object A {[6] } se quedará hasta que object B desaparezca porque B referencia a A . La solución es anular el registro de tus eventos cuando hayas terminado.

Por supuesto, un buen perfil de memoria le permitirá ver sus gráficos de objetos y explorar el anidamiento/referencia de sus objetos para ver de dónde vienen las referencias y qué objeto raíz es responsable (red-gate ants profile, JetBrains dotMemory, memprofiler son realmente buenas opciones, o puede usar el solo texto WinDbg y SOS, pero recomendaría encarecidamente una producto comercial / visual a menos que seas un verdadero gurú).

Creo que el código no administrado está sujeto a sus típicas fugas de memoria, excepto que las referencias compartidas son administradas por el recolector de basura. Podría equivocarme en este último punto.

 109
Author: Karl Seguin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-14 20:34:56

Estrictamente hablando, una fuga de memoria está consumiendo memoria que "ya no es utilizada" por el programa.

"No longer used" tiene más de un significado, podría significar "no más referencia a él", es decir, totalmente irrecuperable, o podría significar, referenciado, recuperable, sin usar, pero el programa mantiene las referencias de todos modos. Solo esto último se aplica a. Net para objetos perfectamente administrados. Sin embargo, no todas las clases son perfectas y en algún momento una implementación subyacente no administrada podría filtre recursos permanentemente para ese proceso.

En todos los casos, la aplicación consume más memoria de la estrictamente necesaria. Los efectos secundarios, dependiendo de la cantidad filtrada, podrían ir de ninguno, a la desaceleración causada por la recolección excesiva, a una serie de excepciones de memoria y, finalmente, un error fatal seguido de terminación forzada del proceso.

Sabe que una aplicación tiene un problema de memoria cuando el monitoreo muestra que se asigna más y más memoria a su proceso después de cada ciclo de recolección de basura . En tal caso, o bien está guardando demasiado en la memoria, o alguna implementación subyacente no administrada se está filtrando.

Para la mayoría de las fugas, los recursos se recuperan cuando se termina el proceso, sin embargo, algunos recursos no siempre se recuperan en algunos casos precisos, los controladores de cursor GDI son notorios por eso. Por supuesto, si tiene un mecanismo de comunicación entre procesos, la memoria asignada en el otro proceso no se liberará hasta que ese proceso la libere o termina.

 33
Author: Coincoin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-01 17:52:46

Creo que las preguntas "qué es una fuga de memoria" y "cuáles son los efectos" ya han sido respondidas bien, pero quería agregar algunas cosas más sobre las otras preguntas...

Cómo entender, si su aplicación fugas

Una forma interesante es abrir perfmon y agregar trazas para # bytes en todos los montones y # colecciones Gen 2 , en cada caso mirando solo su proceso. Si el ejercicio de una característica particular hace que el total de bytes aumentar, y que la memoria permanece asignado después de la próxima generación 2 colección, se podría decir que la característica fugas de memoria.

Cómo prevenir

Se han dado otras buenas opiniones. Solo agregaría que quizás la causa más comúnmente ignorada de las fugas de memoria de.NET es agregar controladores de eventos a los objetos sin eliminarlos. Un controlador de eventos adjunto a un objeto es una forma de referencia a ese objeto, por lo que evitará la recopilación incluso después de todos los demás las referencias se han ido. Recuerde siempre separar los controladores de eventos (usando la sintaxis -= en C#).

¿La fuga desaparece cuando sale el proceso, y qué pasa con la interop COM?

Cuando el proceso sale, toda la memoria asignada a su espacio de direcciones es reclamada por el sistema operativo, incluyendo cualquier objeto COM servido desde DLL. Comparativamente rara vez, los objetos COM se pueden servir desde procesos separados. En este caso, cuando finalice el proceso, es posible que aún sea responsable de la memoria asignado en cualquier proceso de servidor COM que haya utilizado.

 29
Author: Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-26 15:51:52

Definiría fugas de memoria como un objeto que no libera toda la memoria asignada después de que se haya completado. He encontrado que esto puede suceder en su aplicación si está utilizando la API de Windows y COM (es decir, código no administrado que tiene un error o no se administra correctamente), en el marco y en componentes de terceros. También he encontrado que no hacer tiding después de usar ciertos objetos como bolígrafos puede causar el problema.

Personalmente he sufrido Excepciones de Memoria que pueden ser causadas pero no son exclusivos de las fugas de memoria en las aplicaciones dot net. (OOM también puede venir de fijación ver Fijación Artical ). Si no está obteniendo errores de OOM o necesita confirmar si se trata de una fuga de memoria que lo causa, entonces la única manera es perfilar su aplicación.

También trataría de asegurar lo siguiente:

A) Todo lo que implementa Idesposable se dispone utilizando un bloque finally o la instrucción using estos incluyen pinceles, bolígrafos, etc.(algunas personas argumentan para establecer de todo a nada además)

B) Cualquier cosa que tenga un método close se cierra de nuevo usando finally o la instrucción using (aunque he encontrado que usar no siempre se cierra dependiendo de si declaraste el objeto fuera de la instrucción using)

C)Si está utilizando código no administrado/API de Windows que estos se tratan correctamente después. (algunos tienen métodos de limpieza para liberar recursos)

Espero que esto ayude.

 19
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-01 17:57:14

Si necesita diagnosticar una fuga de memoria en. NET, compruebe estos enlaces:

Http://msdn.microsoft.com/en-us/magazine/cc163833.aspx

Http://msdn.microsoft.com/en-us/magazine/cc164138.aspx

Esos artículos describen cómo crear un volcado de memoria de su proceso y cómo analizarlo para que primero pueda determinar si su fuga no está administrada o administrada, y si se administra, cómo averiguar de dónde viene.

Microsoft también tiene un nuevo herramienta para ayudar a generar volcados de bloqueo, para reemplazar ADPlus, llamado DebugDiag.

Http://www.microsoft.com/downloads/details.aspx?FamilyID=28bd5941-c458-46f1-b24d-f60151d875a3&displaylang=en

 19
Author: Eric Z Beard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-19 10:30:03

Usando CLR Profiler de Microsoft http://www.microsoft.com/downloads/details.aspx?familyid=86ce6052-d7f4-4aeb-9b7a-94635beebdda&displaylang=en es una gran manera de determinar qué objetos tienen memoria, qué flujo de ejecución conduce a la creación de estos objetos, y también monitorear qué objetos viven en dónde en el montón (fragmentación, LOH, etc.).

 15
Author: Nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-16 19:54:30

La mejor explicación de cómo funciona el recolector de basura está en Jeff Richters CLR vía C# book, (Ch. 20). Leer esto proporciona una gran base para comprender cómo persisten los objetos.

Una de las causas más comunes de rootear objetos accidentalmente es al conectar eventos outisde una clase. Si conecta un evento externo

Por ejemplo

SomeExternalClass.Changed += new EventHandler(HandleIt);

Y olvídate de desengancharlo cuando te deshagas, entonces alguna clase externa tiene una referencia para tu clase.

Como se mencionó arriba, el SciTech memory profiler es excelente para mostrarle las raíces de los objetos que sospecha que se están filtrando.

Pero también hay una forma muy rápida de comprobar un tipo particular es simplemente usar WnDBG (incluso puede usar esto en el VS.NET ventana inmediata mientras está conectada):

.loadby sos mscorwks
!dumpheap -stat -type <TypeName>

Ahora haz algo que creas que eliminará los objetos de ese tipo (por ejemplo, cierra una ventana). Es útil aquí tener un botón de depuración en algún lugar que se ejecute System.GC.Collect() un par de veces.

Entonces ejecute !dumpheap -stat -type <TypeName> de nuevo. Si el número no fue, o no fue tanto como se puede esperar, entonces usted tiene una base para futuras investigaciones. (Recibí este consejo de un seminario dado por Ingo Rammer ).

 15
Author: Gus Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-19 10:25:19

Supongo que en un entorno gestionado, una fuga sería mantener una referencia innecesaria a una gran parte de la memoria alrededor.

 14
Author: Bernard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-01 15:19:25

¿Por qué la gente piensa que una fuga de memoria en. NET no es lo mismo que cualquier otra fuga?

Una fuga de memoria es cuando se conecta a un recurso y no lo deja ir. Puede hacer esto tanto en la codificación administrada como en la no administrada.

Con respecto a.NET y otras herramientas de programación, ha habido ideas sobre la recolección de basura y otras formas de minimizar las situaciones que harán que su aplicación se filtre. Pero el mejor método para prevenir fugas de memoria es que usted necesita entender su modelo de memoria subyacente, y cómo funcionan las cosas, en la plataforma que está utilizando.

Creer que GC y otra magia limpiarán su desorden es el camino corto a las fugas de memoria, y será difícil de encontrar más adelante.

Al codificar sin administrar, normalmente te aseguras de limpiar, sabes que los recursos que tomas, serán tu responsabilidad de limpiar, no la del conserje.

En.NET por otro lado, mucha gente piensa que el GC limpiará todo. Bien, hace algo por ti, pero necesitas asegurarte de que así sea. . NET envuelve muchas cosas, por lo que no siempre sabe si está tratando con un recurso administrado o no administrado, y necesita asegurarse de con qué está tratando. El manejo de fuentes, recursos de GDI, active directory, bases de datos, etc. son cosas que normalmente debe tener en cuenta.

En términos manejados voy a poner mi cuello en la línea para decir que se va una vez el proceso es eliminado eliminado.

Ya veo sin embargo, mucha gente tiene esto, y realmente espero que esto termine. ¡No puedes pedirle al usuario que termine tu aplicación para limpiar tu desastre! Echa un vistazo a un navegador, que puede ser IE, FF, etc, a continuación, abrir, por ejemplo, Google Reader, dejar que se quede durante algunos días, y mira lo que sucede.

Si luego abre otra pestaña en el navegador, navega a algún sitio, luego cierra la pestaña que alojó la otra página que hizo que el navegador se filtrara, ¿cree que el navegador liberará la memoria? No es así con IE. En mi computer IE comerá fácilmente 1 GiB de memoria en un corto período de tiempo (aproximadamente 3-4 días) si uso Google Reader. Algunos periódicos son aún peores.

 11
Author: neslekkiM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-06 09:04:13

Supongo que en un entorno gestionado, un fuga sería usted mantener un referencia innecesaria a un trozo grande de la memoria.

Absolutamente. Además, no usar el.El método Dispose() en objetos desechables cuando sea apropiado puede causar fugas de mem. La forma más fácil de hacerlo es con un bloque using porque se ejecuta automáticamente .Dispose () al final:

StreamReader sr;
using(sr = new StreamReader("somefile.txt"))
{
    //do some stuff
}

Y si crea una clase que está utilizando objetos no administrados, si no está implementando Identificable correctamente, podría estar causando fugas de memoria para los usuarios de su clase.

 10
Author: Seibar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-05 22:47:49

Estoy de acuerdo con Bernard en lo que sería una filtración de mem en.net.

Podría perfilar su aplicación para ver su uso de memoria, y determinar que si está administrando mucha memoria cuando no debería, podría decir que tiene una fuga.

En términos manejados pondré mi cuello en la línea para decir que desaparece una vez que el proceso es asesinado/eliminado.

El código no administrado es su propia bestia y si existe una fuga dentro de ella, seguirá un mem estándar. definición de fuga.

 10
Author: Pat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-30 21:14:09

Todas las fugas de memoria se resuelven mediante la terminación del programa.

Filtre suficiente memoria y el Sistema Operativo puede decidir resolver el problema en su nombre.

 9
Author: Josh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-04 14:09:47

También tenga en cuenta que.NET tiene dos montones, uno es el montón de objetos grandes. Creo que los objetos de aproximadamente 85k o más grandes se ponen en este montón. Este montón tiene unas reglas de vida diferentes que el montón normal.

Si está creando grandes estructuras de memoria (Diccionarios o Listas) sería prudente buscar cuáles son las reglas exactas.

En cuanto a la recuperación de la memoria en la terminación del proceso, a menos que su Win98 en ejecución o sus equivalentes, todo se libera de nuevo al sistema operativo en la terminación. Las únicas excepciones son las cosas que se abren entre procesos y otro proceso todavía tiene el recurso abierto.

Los objetos COM pueden ser complicados. Si siempre usas el patrón IDispose, estarás a salvo. Pero me he encontrado con algunos ensamblajes de interop que implementan IDispose. La clave aquí es llamar Marshal.ReleaseCOMObject cuando haya terminado con él. Los objetos COM todavía utilizan el conteo de referencia COM estándar.

 7
Author: Joel Lucsy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-26 15:52:26

He encontrado . Net Memory Profiler una muy buena ayuda al encontrar fugas de memoria en. Net.No es gratis como el Microsoft CLR Profiler, pero es más rápido y más al punto en mi opinión. A

 6
Author: Lars Truijens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-20 18:39:25

Una definición es: No se puede liberar memoria inalcanzable, que ya no se puede asignar a un nuevo proceso durante la ejecución del proceso de asignación. En su mayoría se puede curar mediante el uso de técnicas de GC o detectado por herramientas automatizadas.

Para obtener más información, visite http://all-about-java-and-weblogic-server.blogspot.in/2014/01/what-is-memory-leak-in-java.html.

 1
Author: hemant kurmi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-15 16:00:47