Monitorizar el uso de memoria de nuestras aplicaciones .NET

En aquellas aplicaciones de cierto tamaño, donde el consumo de memoria se convierte en un tema a tener en cuenta, es importante que se considere el consumo de memoria desde las primeras fases de diseño de la aplicación, o las consecuencias después serán peores y más difíciles de arreglar, como veremos a lo largo del presente artículo. Típicamente, las aplicaciones se pueden clasificar en pequeñas (<20Mb e consumo de memoria RAM), medianas  entre 20Mb y 50Mb) y grandes (>50Mb). Cuanto mayor es el consumo de memroria de una aplicación, más  mportante es tenerlo en cuenta desde las primeras fases de diseño de dicha aplicación.

¿Cómo afecta el uso de memoria al desempeño?

Recordemos que un computador normal tiene al menos 3 niveles de memoria: L1 y L2 que son típicamente cachés on-chip, de baja capacidad y muy rápido acceso, una posible L2 on-board y la propia memoria RAM. Después está el disco, pero si estamos contando con él como sistema de memoria estamos perdidos, pues su velocidad de acceso es  0.000 veces más lento que el de una RAM.

Existen tres tipos de cuellos de botella a tener en cuenta para toda aplicación:
– Rutas de acceso a datos que se utilizan continuamente, y que deberán ser traídos continuamente como operandos a las cachés. Si estos conjuntos de datos son muy grandes, no podrán ser ubicados en las cachés de una forma más o  menos permanente y útil para el desempeño.
– Primer arranque de una aplicación. Lo que se conoce como “arranque frío”. El problema de este arranque es que  todos los datos del programa deben ser traídos de disco. El desempeño se ve afectado aquí por los datos e  instrucciones que utiliza el propio programa, no la memoria que va a utilizar, el montículo o la pila de llamadas, detalles que son gestionados por el sistema operativo.
– Cambios de aplicación. En un entorno típico multitarea donde conviven varias aplicaciones en memoria y se dan los fenómenos de concurrencia y planificador en la CPU, cada vez que se cambia de aplicación por parte del usuario para trabajar en dicha aplicación se produce un robo de memoria entre aplicaciones, lo cual se traduce en un intercambio a disco de las páginas que deben ser desalojadas para que sean utilizadas por la nueva aplicación que tiene el “foco”. Este consumo afecta no solamente a los datos del programa e instrucciones como ocurría en el caso anterior, sino a  toda la memoria que utiliza un programa, pues las páginas que se trasladan contienen datos, pila, etc.

¿Qué puedo hacer para mejorar el consumo de memoria de mis aplicaciones?

Existen tres modos en los que se puede pellizcar un poco el uso de memoria. Todos ellos se ven afectados por el  diseño de los propios algoritmos, que son los que dictan cómo se accede a memoria.
– Ejecutar menos código al inicio, lo cual favorece el arranque frío.
– Tocar menos datos, lo cual favorece el primer factor que explicamos antes.
– Modificar las estructuras de datos para utilizar otras más eficientes, que también favorece el primer factor.

La mayor parte de las veces lo que se suele hacer es optar por la tercera solución, lo cual implica retocar sensiblemente el código, con los costes que ello conlleva, no sólo de rediseño, y desarrollo sino que también de  testing. Es por esto por lo que es importante pensar en la eficiencia de la memoria desde las primeras fases de desarrollo si preveemos un consumo de memoria importante, porque luego pueden venir los problemas.

Monitorizando procesos

Para monitorizar procesos, se puede utilizar el Task Manager como primera aproximación. Esta herramienta nos aportará valiosa información de cada proceso, como PID, memoria compartida y memoria privada.

La memoria compartida de un proceso se refiere generalmente a las instrucciones, que son de sólo lectura. La  memoria privada, por otro lado, está constituida principalmente por los datos locales de cada proceso, que son datos de lectura y escritura. Sin embargo, hay un tipo de memoria que no aparece en el Task Manager y que hay que tener en cuenta, precisamente porque es el mayor cuello de botella de todo proceso: el sistema de ficheros. Cada vez que se accede al sistema de ficheros se incurre en una penalización notable en el rendimiento del proceso que en muchos casos es inevitable.

Otra herramienta más avanzada para la monitorización del uso de memoria es VADump, que aporta información hasta el nivel de DLL’s.
En el artículo que se referencia más abajo encontrará más información acerca de esta herramienta.

El recolector de basura de .NET.

El recolector de basura elimina regiones de memoria que no son utilizadas más por un proceso. Existen algunas posibilidades de manipulación del recolector que permite mejorar el consumo de memoria. Para ello hay que entender cómo se organiza dicho recolector en .NET.

Una optimización muy importante es que el GC no busca en todo el montículo de objetos cada vez que es ejecutado, sino que divide el montículo en tres “generaciones”:

– GC0: la más pequeña y rápida, solamente busca candidatos a limpiar entre las nuevas localizaciones ocupadas de memoria tras la última pasada del GC. Idealmente, el tamaño de esta generación es menor que la L2.
– GC1: selecciona las localizaciones que sobrevivieron a la última pasada del GC. Es más lento de ejecutar que la GC0.
– GC2: recorre todos los objetos. La más lenta, por tanto, de hecho el tiempo que tarda en pasar es significativo. Este tiempo que tarda en recorrer todos los objetos crece de una forma más o menos lineal con el tamaño del montículo. El coste real depende de la cantidad de memoria que sigue estando ocupada por el proceso, el número de punteros del GC a dicha memoria y cómo de fragmentado esté el montículo.

Una herramienta que permite monitorizar con precisión el uso del GC es PerfMon. Para más información acerca de dicha herramienta, léase el artículo que se referencia al final.


Referencias:
“Memory Usage Auditing for .NET Applications”
Subramanian Ramaswamy & Vance Morrison
MSDN Magazine
June 2009

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s