"La Gaceta de Linux...¡haciendo de Linux algo un poco más divertido!"


¿Tu memoria no es lo que solía ser?

Por Madhu M Kurup

Traducción al español por Jesús Fuenlabrada
el día 17 de Febrero de 2003, para La Gaceta de Linux


Intención

La intención de este artículo es proveer conocimientos acerca de las herramientas de detección de pérdidas de memoria y perfilado disponibles actualememte. También tiene intención de proveerte de suficiente información como para ser capaz de hacer una elección entre las diferentes herramientas que puedes necesitar.

Pérdidas y Corrupción

Estamos hablando aquí de software, no de cañerías. Y si, cualquier programa no trivial medianamente largo está sujeto a tener problemas con la memoria y o las pérdidas.

¿Dónde ocurren los problemas?

Primero, las pérdidas y problemas similares de memoria no ocurren en algunos lenguajes. Estos lenguajes creen que la gestión de la memoria es tan importante que nunca debe ser manejada por los usuarios de esos lenguajes. Está mejor manejada por los diseñadores del lenguaje. Ejemplos de tales lenguajes son Perl, Java y similares.
    No obstante, en algunos otros lenguajes (principalmente C y C++) los diseñadores del lenguaje han sentido que la gestión de memoria es tan importante que solamente puede ser cuidada por los usuarios del lenguaje. Una pérdida se dice que ocurre cuando dinámicamente has asignado memoria y después te has olvidado de devolverla. En adición a las pérdidas, ocurren otros problemas de memoria como sobrecarga de buffers, punteros colgantes cuando los programadores gestionan la memoria ellos mismos. Estos problemas están casusados donde hay una discrepancia entre lo que el programa (y por extensión el programador) cree que es el estado de la memoria, en oposición a lo que realmente es.

¿Qué son los problemas?

Para que los programas sean capaces de tratar con datos cuyo tamaño no es conocido en tiempo de compilación, el programa puede necesitar requerir memoria del entorno de ejecución (sistema operativo). No obstante, habiendo obtenido un pedazo de memoria, puede ser posible que el programa no lo devuelva al entorno después de su uso. Un condición incluso más severa resulta cuando la dirección del bloque que fue obtenido se pierde, lo que significa que no es posible identificar la memoria asignada. Otros problemas incluyen el intento de acceder a la memoria después de que ha sido devuelta (punteros colgantes). Otro problema común es intentar acceder a más memoria de la que originalmente se pidió (sobrecarga de buffers).

¿Por qué deben molestarme estos problemas?

Las pérdidas no son un problema para programas de vida corta que finalizan su trabajo rápidamente. Desgraciadamente, muchos programas están diseñados para trabajar sin fin durante un largo período de tiempo. Un buen ejemplo podría ser el servidor web Apache que está actualmente sirviendo esta página web. En tal situación, un programa funcionando mal por pérdidas puede guardar la memoria requerida al sistema operativo y no devolverla. Eventualmente esto puede llevar al sistema a quedarse sin memoria y todos los programas ejecutándose en esa máquina lo sufrirían. Esto no es obviamente una cosa buena. En adición a un programa pidiendo mucha memoria, las pérdidas pueden también hacer a un programa lento. La velocidad a la cual el programa es cambiado de contexto dentro y fuera puede decrecer si la carga de la memoria se incrementa. Aunque no tan severo como para causar a la máquina que se rompa en pedazos, una carga excesiva de memoria en la máquina podría causar su derrota, cambiando datos adelante y atrás.
   Los punteros colgantes pueden resultar en corrupción y fallos que son extremadamente inusuales, oscuros y duros de resolver. Las sobrecargas de buffers son probablemente las más peligrosas de las tres formas de problemas de memoria. Pueden ser la causa de la mayoría de los agujeros de seguridad de los que oyes hablar [Programación Segura]. Adicionalmente a los problemas descritos arriba, puede ser posible que el mismo bloque de memoria sea devuelto al sistema múltiples veces. Esto indica obviamente un error de programación. Un programador vería como son hechas las peticiones de memoria a lo largo de la vida de un programa para encontrar y solucionar los problemas.

Combatiendo estos problemas

Hay algunos mecanismos en tiempo de ejecución para combatir los problemas de memoria. Las pérdidas pueden ser solucionadas parando y rearrancando periódicamente el programa ofensivo [OOM]. Los punteros colgantes pueden volverse a utilizar llenando de ceros toda la memoria devuelta a los sistemas operativos. Las sobrecargas de buffers tienen una variedad de soluciones, algunas de las cuales esán descritas con más detalle aquí.
    Típicamente, la sobrecarga de combatir estos problemas en tiempo de ejecución o en las últimas etapas del ciclo de desarrollo es tan alto que encontrarlos y solucionarlos en el nivel del programa es a menudo la solución más óptima.

Open Source

Alternativas basadas en GCC

La herramienta gcc incluye ahora un recolector de basura que facilita la detección y eliminación fáciles de muchos problemas de memoria. Notar que mientras puede ser usado para detectar pérdidas, la razón primaria para crearlo fue implementar un buen recolector de basura [Recolectores de Basura]. Este trabajo está actualmente liderado por Hans-J. Boehm en HP.

Tecnología

La tecnología usada es la técnica de Boehm-Demers-Weiser para llevar el control de la memoria asignada. La asignación de memoria se hace usando la versión algorítmica de las funciones estándar de asignación de memoria. El programa es entonces compilado con estas funciones y cuando se ejecuta, el algoritmo puede analizar el comportamiento del programa. Este algoritmo es muy bien conocido y bien comprendido. No puede causar problemas y/o interferir con los programas. Puede ser hecho "thead safe" (seguro para hilos) y puede incluso escalar a un sistema multiprocesador.

Rendimiento

Presenta un buen rendimiento con una reducción en velocidad en línea con las expectativas. El código es extremadamente portable y está también disponible directamente con gcc. La versión empaquetada con gcc es ligeramente antigua, pero puede ser actualizada.
    No hay interface - es difícil de usar y requiere mucho esfuerzo para que sea útil. Los sistemas existentes pueden no tener esta configuración del compilador y requerir algún trabajo adicional para funcionar. En resumen, para que las llamadas sean atrapadas, todas las llamadas a memoria (tales como malloc() y free() ) tienen que ser reemplazadas con las equivalentes proporcionadas por el recolector de basura. Se puede usar una macro, pero no es todavía muy flexible. Esta aproximación también requiere implícitamente que el código fuente de todas las piezas que necesiten perfilado de memoria que tengan la habilidad de cambiar a las funciones reales.

Veredicto

Si necesitas una solución para múltiples plataformas (arquitecturas, sistemas operativos) donde tengas el control sobre todas las fuentes relevantes, ésta puede ser.

Memprof

Memprof es un atractivo paquete fácil de usar, creado por Owen Talyor de Red Hat. Esta herramienta es un buen front-end de GNOME al recolector de basura de Boehm-Demers-Weiser.

Tecnología

En el nucleo de perfilado, memprof no es diferente a la herramienta descrita arriba. No obstante, como se implementa esta funcionalidad es capturando todas las peticiones de memoria desde el programa y redirigiédolas en tiempo de ejecución al recolector de basura. Aunque no es tan funcional como la alternativa de gcc en los hillos y multiprocesadores, se puede pedir al programa que siga los "forks" cuando ocurran.

Rendimiento

El rendimiento de esta herramienta es muy bueno. El entorno gráfico de usuario está bien diseñado, digno de confianza e informativo. Esta herramienta trabaja directamente con los ejecutables, sin ningún cambio en los fuentes. Esta herramienta también presenta gráficamente el perfil de memoria cuando el programa se ejecuta lo que ayuda a comprender los requerimientos de memoria del programa durante su ciclo de vida.
    Esta herramienta esta disponible actualmente únicamente para las arquitecturas x86 y PPX sobre Linux. Si necesitas ayuda en otras plataformas, tendrás que mirar en otro sitio. Esta herramienta no es una aplicación GTK, necesita el entorno completo GNOME. Esto puede hacerlo no útil en todos los sistemas. Finalmente, el desarrollo de esa herramienta parace estático (version 0.4.1. por el momemto). Aunque es posible que lo que se require que haga lo haga bien, no parece que esta herramienta haga nada más que la detección de pérdidas.

Verdicto

Si te gustan los Interfaces Gráficos de Usuario y no te importa tener GNOME y Linux, esta es la herramienta para ti.

Valgrind

Valgrind es un programa que intenta resolver un conjunto completo de problemas de memoria, donde las pérdidas son solamente uno de ellos. Esta herramienta es el producto de Julian Seward (conocido por bzip2 y cacheprof). Se define a si mismo como "un depurador de memoria de código libre para linux x86" y ciertamente cumple lo que dice. Además, puede perfilar el uso del caché de la CPU, algo que es muy inusual.

Tecnología

La tecnología usada en este programa es muy compleja y está bien documentada. Cada byte de memoria asignado por el programa es seguido por nueve bits de estado, que son usados para identificar lo que se está haciendo. A costa de incrementar tremendamente la carga de la memoria de la ejecución de un programa, esta herramienta permite un gran conjunto de comprobaciones. Como todas las lecturas y escrituras son interceptadas, el perfilado de varias L cachés de la CPU puede ser también hecho.

Rendimiento

Esta herramienta es la más lenta de las tres detalladas aquí, por razones obvias. No obstante, a pesar de la reducción de velocidad, esta herramienta provee tanta información que es probablemente la más detallada de las tres. Además de los temas habituales, esta herramienta puede identificar una variedad de otros problemas de memoria e incluso algunos problemas con pthreads POSIX. La información de caché es probablemente innecesaria para la mayoría de las aplicaciones, pero es un camino interesante de mirar el rendimiento de una aplicación. El mayor valor añadido que aporta Valgrind es que está bajo un desarrollo muy rápido con un desarrollador proactivo y una comunidad activa. De hecho la página web de Valgrind proclama lo siguiente del autor -   "Si tienes problemas con Valgrind, no sufras en silencio. Escribeme".
    La herramienta no obstante, es muy específica de x86. La portabilidad se limita a Linux x86. El interface es únicamente en línea de comandos y aunque es usable, a veces la herramienta da demasiada información para ser útil. Esta herramienta trabaja también directamente con binarios, pero aunque no requiere que se recompìle, requiere diligencia para navegar en la salidad de esta herramienta para encontrar lo que estás buscando. Puedes suspender el perfilado de memoria para las librerías del sistema creando ficheros de supresión, pero escribir esos ficheros no es fácil. Además, el soporte de hilos no es completo, aunque esta herramienta ha sido usado en Mozilla, OpenOffice y otros programas grandes con hilos. Si la herramienta tuviera un Interfaz Gráfico de Usuario, ganaría sin levantar las manos.

Verdicto

Si estás en x86 y conoces tu código bien y no te importa un interface de texto este programa te llevará a otro nivel.

Otras Herramientas de Código Libre

Antes de ser enviado a la hoguera por no haber mencionado tu herramienta favorita de memoria, debo confesar que solamente he comparado en profundidad estas tres herramientas en términos de los datos que proveen. Una lista más comprehensiva de las herramientas de detección de pérdidas está disponible aquí.

Comerciales

Estas herramientas se mencionan aquí únicamente por completitud.

Purify

El gran padre de las herramientas de memoria, no funciona en Linux, así que ya puedes parar de preguntar esa cuestión.

Geodesic

Un recién llegado a esta arena, Geodesic es más conocido en la comunidad Linux por su demo de Mozilla, en la que han usado sus herramientas para ayudar a encontrar problemas de memoria en la base de código de Mozilla. Funciona una versión completamente funcional para Solaris/Linux. Funciona en Windows también.

Insure++

Una herramienta Específica C++, pero muy conocida, Insure++ de Parasoft es una herramienta muy completa de perfilado de memoria y detección de pérdidas. Además, puede encontrar algunos errores específicos de C++, que nunca viene mal. Esta herramienta funciona con una variedad de compiladores y sistemas operativos, y una versión de prueba gratuita está disponible.

Notas Varias:

Programación Segura

La Programación Segura involucra muchos componentes, pero probablemente el más significativo es el uso cuidadoso de la memoria. Están disponibles más detalles  aquí.

Asesinos OOM

Algunos de los nuevos kernles de Linux emplean un algoritmo que es conocido como asesino OOM (Out Of Memory). Este código se invoca cuando el kernel se queda sin memoria. Más detalles están disponibles en aquí.

Recolectores de Basura

Una de las razones por las que la recolección de basura no es siempre la solución preferida es que realmente difícil de implementar. Tienen graves problemas con las estructuras auto-referenciadas (es decir estructuras que se enlazan a si mismas) como se describe aquí.

Madhu M Kurup

Soy un ingeniero en Ciencia de Computadores de Bangalore, India y perteneciente a ILUG Bangalore. He estado trabajando y jugando con Linux desde hace un tiempo y mientras programar es mi primer amor, Linux es el segundo. Trabajo en el grupo de Data Mining de Yahoo! Inc en algoritmos, escalabilidad y APIs. Duermo con el cliente de mensajes de Linux y me intereso superficialmente en varios proyectos de software cuando (si) puedo encontrar algo de tiempo libre.

Y sí, si lo quieres saber, uso C++, vi, mutt, Windowmaker y Mandrake; empieza la guerra de las banderas :)


Copyright © 2002, Madhu M Kurup.
Licencia de Copiado http://www.linuxgazette.com/copying.html
Publicado en el Número 81 de Linux Gazette, Agosto 2002