2012-04-06 9 views
6

tengo la siguiente situación muy extraña y problema:¿Cómo detectar la fuga de memoria .NET WPF o el funcionamiento prolongado del GC?

  • .NET 4.0 aplicación para la edición de diagrama (WPF).

  • Funciona bien en mi PC: 8 GB de RAM, 3.0 GHz, i7 de cuatro núcleos.

  • Al crear objetos (sobre todo diagramas de nodos y conectores, más toda la información de deshacer/rehacer), el Administrador de tareas muestra, como se esperaba, algunos usos de memoria "saltos" (arriba y abajo).

  • Estos "saltos" de uso de mem también se siguen ejecutando DESPUÉS de que finalizó la interacción del usuario. Tal vez esta es la memoria de limpieza/reorganización de GC?

  • Para ver lo que está pasando, he usado el generador de perfiles de las hormigas, pero de alguna manera evita que esos "saltos" ocurran después de la interacción del usuario.

PROBLEMA: Se congela/bloquea después de segundos o minutos de uso en algunos laptos/débiles/netbooks lentos de mis probadores beta (menores de 2 GHz de velocidad y bajo 2 GB de RAM). Estaba pensando en una pérdida de memoria, pero ...

EDIT 1: Además, existe el caso de que el uso de memoria crece y crece hasta el colapso (solo en máquinas lentas).

  • En una máquina Windows XP Mode (VM en Win 7), con sólo 512 MB de RAM Asignado funciona bien sin el uso de mem- "saltos" después de interacción con el usuario (no hay limpieza GC ?!).

EDIT 2: El problema es peor cuando el sistema tiene algunos otros programas pesados ​​en ejecución (como Visual Studio, Office y páginas web abiertas). Ni siquiera se puede crear el primer símbolo del diagrama mientras el uso de la memoria se dispara como un cohete al espacio (cientos de MB consumidos en segundos). ¿Alguien con experiencias similares? ¿Cuáles fueron sus estrategias?

Entonces, realmente tengo un gran problema porque no puedo reproducir el error, solo veo estos comportamientos extraños (saltos de memoria), y la herramienta que se supone que me muestra lo que está ocultando el problema (como la "paradoja del observador")

¿Alguna idea de lo que está pasando y cómo resolverla?

EDIT 3: Esta captura de pantalla del perfilador de memoria Ants muestra que el enorme consumo de RAM (en crescendo) si proviene de recursos no administrados.

enter image description here

Pero, lo que puede estar consumiendo tanta memoria, tan rápido ?? !!!

+0

Después de agregar una llamada GC.Collect() después de cada ejecución de comandos (aquellos que crean nodos y conectores en el diagrama, más la información de deshacer/rehacer) el resultado es casi el mismo en la PC lenta. –

+0

Responde a esta pregunta. Pero el problema sigue sin resolverse. Suponiendo que se encuentra el código no administrado que causa el problema, ¿qué haría? póngase en contacto con el fabricante del componente nativo o la biblioteca para informarles de un error? –

Respuesta

3

Esto sugeriría que es probable que esté creando una gran cantidad de "basura", básicamente, crear y dejar que muchos objetos salgan del alcance rápidamente, pero que tarden lo suficiente como para entrar en Gen1 o Gen2. Esto supone una gran carga para el GC, que a su vez puede causar heladas y cuelga en muchos sistemas.

Para ver qué está pasando, he usado el generador de perfiles de las hormigas, pero de alguna forma evita que esos "saltos" ocurran después de la interacción del usuario.

La razón por la que este generador de perfiles (ANTS), específicamente, podría enmascarar este comportamiento es que obliga a un GC completo cada vez que toma una instantánea de memoria. Esto haría que parezca que no hay "fuga" de memoria (como no lo hay), pero no muestra la presión de memoria total en el sistema.

Una herramienta como PerfView se podría utilizar para investigar el comportamiento del GC durante el tiempo de ejecución del proceso. Esto lo ayudaría a rastrear la cantidad de GC que ocurren y su estado de aplicación en ese momento.

+0

Ya veo ... Aprenderé más y mejoraré GC en la medida de lo posible. Y, por supuesto, usaré la herramienta PerfView para ver qué más puedo descubrir. ¡Muchas gracias! –

2

Es difícil saber exactamente lo que está pasando sin ver su código, pero aquí hay algunas sugerencias:

En primer lugar, alguna información sobre el recolector de basura. Lo más importante que debe saber es que el GC no es determinista, no puede saber cuándo se ejecutará. Incluso llamar a GC.Collect() es solo una sugerencia, no un comando. El montón Gen0 es para objetos con ámbito local y se recopila con frecuencia. Si un objeto sobrevive a la colección Gen0, se moverá al montón Gen1. Después de un poco, se recogerá el montón de Gen1 y si un objeto sobrevive a la recopilación, se mueve al montón Gen2, que se recoge con menos frecuencia. Por esta razón, es posible ver un patrón de diente de sierra en un gráfico de memoria si está asignando muchos objetos que lo convierten en el montón Gen1 o Gen2.

Usando una herramienta como Process Explorer examine el tamaño de los montones administrados (Gen0, Gen1, Gen2 y el montón de objetos grandes) y descubra dónde se está reteniendo la memoria. Si tiene muchos objetos efímeros (pila Gen1), piense en una forma de reutilizar la memoria en lugar de volver a asignarla; algo así como object pool funciona bien para eso.

Además, intente comparar el tamaño total de los montones administrados con los bytes privados totales de su aplicación. Los bytes privados incluyen tanto la memoria administrada como la no administrada asignada por su aplicación. Si hay una gran diferencia entre el tamaño de los montones administrados y los bytes privados, es probable que su aplicación asigne objetos no administrados (a través de objetos gráficos, flujos de datos, etc.) que no se eliminen correctamente. Busque objetos que implementen IDisposable, pero no haga que se llame a Dispose().

Otro problema podría ser la fragmentación del montón. Si su aplicación está asignando objetos grandes que no cabe en el montón actual, solicitará más memoria del sistema operativo. Una solución para evitar esto es asignar trozos o memoria más pequeños o asignarlos en bloques secuenciales en lugar de al azar (piense en la matriz frente a la lista vinculada). Una herramienta como ANTS Memory Profiler debería poder decirle que esto está sucediendo.

La recomendación de @ReedCopsey de PerfView (o su predecesor, el CLR Profiler) es una buena idea y le dará una mejor idea de cómo se asigna su memoria.

5

Lo que usted describe es un comportamiento totalmente normal para un programa .NET, no hay indicación de que haya algún problema con su código.

El problema más grande es que TaskMgr.exe no es un programa muy bueno para decirte lo que está sucediendo en tu proceso. Muestra el "conjunto de trabajo" para un proceso, un número que tiene muy poco que ver con la cantidad de memoria que usa el proceso.

El conjunto de trabajo es la cantidad de RAM que utiliza su proceso. Cada proceso obtiene 2 gigabytes de memoria virtual para usar para código y datos. Incluso en su caja virtual de XP con solo 512 MB de RAM. Sin embargo, todos estos procesos tienen solo una cantidad de RAM establecida para trabajar. En una máquina pequeña que puede ser tan poco como un gigabyte.

Al tener múltiples procesos en ejecución, cada uno con gigabytes de memoria virtual con solo un gigabyte de memoria real requiere algo de magia. Eso es proporcionado por el sistema operativo, Windows virtualiza la RAM. En otras palabras, crea la ilusión para cada proceso que se ejecuta por sí mismo en una máquina con 2 gigabytes de RAM. Esto se hace mediante una función llamada paginación, cuando un proceso necesita leer o escribir en la memoria, el sistema operativo toma una porción de RAM para proporcionar la memoria física.

Inevitablemente, tiene que tomar de distancia parte de la RAM de otro proceso para que pueda estar disponible para los suyos. Cualquier cosa que haya estado previamente en ese trozo de RAM necesita ser preservada. Eso es lo que hace el archivo de paginación , almacena el contenido de la RAM que se paginó.

Claramente, esto no es gratis, los discos son bastante lentos y la paginación es una operación costosa. Es por eso que las máquinas de bajo rendimiento tienen un rendimiento pobre cuando les pides que ejecuten varios programas grandes. La medida real para esto también es visible en TaskMgr.exe pero tienes que agregarlo. Ver + Seleccionar columnas y marcar "Delta de error de página". Observe este número mientras se ejecuta su proceso. Cuando lo veas como máximo, puedes esperar que tu programa disminuya mucho y el uso de la memoria que se muestra cambie rápidamente.

Direccionamiento de sus observaciones:

creación de objetos ... el programa administrador de tareas, como era de esperar, el uso de memoria algunos "saltos"

Sí, está utilizando la memoria RAM por lo que el conjunto de trabajo sube .

Estos mem-uso "saltos" también se mantiene ejecutar después de la interacción del usuario terminó

No mates, pero otros procesos obtienen más tiempo para ejecutar, utilizando la memoria RAM a su vez y chocando algunos de los suyos a cabo. Verifique la columna delta de falla de página.

He utilizado el generador de perfiles de las hormigas, pero algo impide que esos "saltos" sucedan después de la interacción del usuario.

Sí, los perfiladores de memoria se centran en el uso real de la memoria de su programa, el tipo de memoria virtual. En su mayoría ignoran el conjunto de trabajo, no hay nada que puedas hacer al respecto y el número no tiene sentido porque realmente depende de qué otros procesos se están ejecutando.

no es el caso de que el uso de la memoria crece y crece hasta que el colapso

que puede ser un efecto secundario de la recolector de basura, pero eso no es típico. Probablemente esté viendo a Windows recortar su conjunto de trabajo, tirando páginas para que no consuma demasiadas.

En una máquina Windows XP Mode (VM en Win 7), con sólo 512 MB de RAM asignada funciona bien

Eso es probablemente porque no ha instalado ningún programa de grandes en que WM que competiría para RAM XP también fue diseñado para funcionar bien en máquinas con muy poca memoria, es liso en una máquina con 256 MB. Definitivamente no es el caso de Vista/Win7, fueron diseñados para aprovechar el hardware de la máquina moderna. Una característica como Aero es un bonito eye candy pero muy caro.

El problema es peor cuando el sistema tiene algunos otros programas que se ejecutan pesados ​​

Sí, usted está compitiendo con los otros procesos que requieren mucha memoria RAM.

Ni siquiera el primer símbolo de diagrama se puede crear, mientras que el uso de la memoria despega como un cohete

páginas Sí, que está viendo siendo asignada de nuevo a la memoria RAM, siendo recargado desde el archivo de paginación y los archivos ngen-ed .ni.dll. Aumentando rápidamente tu conjunto de trabajo nuevamente. También verá el número del delta del error de página en pico.

Concluyendo, su programa WPF solo consume mucha memoria y necesita la potencia necesaria para funcionar bien. No es fácil de arreglar, se necesita un rediseño bastante drástico para reducir los requisitos de recursos. Así que simplemente ponga los requisitos del sistema en la caja, es completamente normal hacerlo.

+0

No estoy de acuerdo con su conclusión. Mi aplicación no consume tanta memoria, es otra cosa ... GC ?, GD + ?, u otro elemento no administrado, como lo muestra el generador de perfiles de la memoria, y ocurre en algunas circunstancias nebulosas. –

+0

Toda la evidencia que presentó de hecho muestra que su aplicación usa mucha memoria virtual. Es bastante visible en la captura de pantalla del perfilador, 700 megabytes es un pedazo de buen tamaño. No está del todo claro para mí qué evidencia usaste para insistir en que no es así. Los perfiladores no son muy buenos para desglosar el uso de la memoria no administrada. Porque es, bueno, no administrado. Comúnmente se usa para cosas como mapas de bits, BitmapSource es una clase administrada muy pequeña pero envuelve una gran cantidad de datos no administrados. Los píxeles del mapa de bits. –

+0

Lo que quería decir es que todavía no puedo ver nada incorrecto en mi código (que se administra). Teniendo en cuenta que la fuga está en la memoria no administrada, el programa solo carga algunos gráficos (pantalla de inicio, más iconos de botón) y no tengo tareas en segundo plano funcionando, solo puedo deducir que hay un componente fuera de mi control que tiene la fuga. –

Cuestiones relacionadas