En el código C / C ++ no administrado, ¿cuáles son las mejores prácticas para detectar pérdidas de memoria? ¿Y las pautas de codificación a evitar? (Como si fuera así de simple;)
En el pasado, hemos utilizado un poco tonto: tener un incremento de contador para cada llamada de asignación de memoria y decremento mientras se libera. Al final del programa, el valor del contador debe ser cero.
Sé que esta no es una buena manera y hay algunas capturas. (Por ejemplo, si está liberando memoria asignada por una llamada de API de plataforma, su recuento de asignación no coincidirá exactamente con su recuento de liberación. Por supuesto, incrementamos el contador al llamar a llamadas de API que asignaron memoria).
Espero sus experiencias, sugerencias y quizás algunas referencias a herramientas que simplifiquen esto.
fuente
Respuestas:
Si su código C / C ++ es portátil a * nix, pocas cosas son mejores que Valgrind .
fuente
Si está utilizando Visual Studio, Microsoft proporciona algunas funciones útiles para detectar y depurar pérdidas de memoria.
Comenzaría con este artículo: https://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.140).aspx
Aquí está el resumen rápido de esos artículos. Primero, incluya estos encabezados:
Entonces debe llamar a esto cuando su programa salga:
Alternativamente, si su programa no sale en el mismo lugar cada vez, puede llamar a esto al comienzo de su programa:
Ahora, cuando el programa salga, todas las asignaciones que no se liberaron se imprimirán en la Ventana de salida junto con el archivo en el que se asignaron y la aparición de la asignación.
Esta estrategia funciona para la mayoría de los programas. Sin embargo, se vuelve difícil o imposible en ciertos casos. El uso de bibliotecas de terceros que realizan algunas inicializaciones en el inicio puede hacer que aparezcan otros objetos en el volcado de memoria y puede dificultar el seguimiento de sus fugas. Además, si alguna de sus clases tiene miembros con el mismo nombre que cualquiera de las rutinas de asignación de memoria (como malloc), las macros de depuración de CRT causarán problemas.
Hay otras técnicas explicadas en el enlace de MSDN mencionadas anteriormente que también podrían usarse.
fuente
En C ++: use RAII. Punteros inteligentes como
std::unique_ptr
,std::shared_ptr
,std::weak_ptr
son sus amigos.fuente
Como desarrollador de C ++, aquí hay algunas pautas simples:
En cuanto a la detección de pérdidas de memoria personalmente, siempre he usado el Detector de fugas visual y considero que es muy útil.
fuente
He estado usando DevStudio durante demasiados años y siempre me sorprende cuántos programadores no saben acerca de las herramientas de análisis de memoria que están disponibles en las bibliotecas de tiempo de ejecución de depuración. Aquí hay algunos enlaces para comenzar:
Seguimiento de solicitudes de asignación de montón : específicamente la sección sobre números únicos de solicitud de asignación
_CrtSetDbgFlag
_CrtSetBreakAlloc
Por supuesto, si no está utilizando DevStudio, esto no será particularmente útil.
fuente
Me sorprende que nadie haya mencionado DebugDiag para el sistema operativo Windows.
Funciona en versiones de lanzamiento, e incluso en el sitio del cliente.
(Solo necesita mantener los PDB de su versión de lanzamiento y configurar DebugDiag para usar el servidor de símbolos públicos de Microsoft)
fuente
Visual Leak Detector es una herramienta muy buena, aunque no admite las llamadas en tiempos de ejecución VC9 (MSVCR90D.DLL, por ejemplo).
fuente
Microsoft VC ++ en modo de depuración muestra pérdidas de memoria, aunque no muestra dónde están las pérdidas.
Si está utilizando C ++ siempre se puede evitar el uso de nuevo de forma explícita: usted tiene
vector
,string
,auto_ptr
(Pre C ++ 11; reemplazado porunique_ptr
en C ++ 11),unique_ptr
(C ++ 11) yshared_ptr
(C ++ 11) en su arsenal.Cuando lo nuevo es inevitable, intente ocultarlo en un constructor (y ocultar eliminar en un destructor); Lo mismo funciona para API de terceros.
fuente
Hay varias bibliotecas de "malloc" de reemplazo que le permitirán llamar a una función al final y le informará sobre toda la memoria no liberada y, en muchos casos, quién la mallovó (o no) en primer lugar. .
fuente
Si está utilizando MS VC ++, le recomiendo esta herramienta gratuita del proyecto de código: leakfinder de Jochen Kalmbach.
Simplemente agregue la clase a su proyecto y llame
antes y después del código que desea verificar si hay fugas.
Una vez que haya compilado y ejecutado el código, Jochen proporciona una herramienta GUI ordenada donde puede cargar el archivo .xmlleaks resultante y navegar a través de la pila de llamadas donde se generó cada fuga para buscar la línea de código ofensiva.
PurifyPlus de Rational (ahora propiedad de IBM) ilustra las fugas de manera similar, pero creo que la herramienta de detección de fugas es realmente más fácil de usar, ¡con la ventaja de que no cuesta varios miles de dólares!
fuente
Nunca lo usé yo mismo, pero mis amigos de C me dicen Purify .
fuente
Si está utilizando Visual Studio, puede valer la pena mirar Bounds Checker . No es gratis, pero ha sido increíblemente útil para encontrar fugas en mi código. Tampoco solo pierde pérdidas de memoria, sino también pérdidas de recursos GDI, errores de uso de WinAPI y otras cosas. Incluso le mostrará dónde se inicializó la memoria filtrada, por lo que es mucho más fácil rastrear la filtración.
fuente
Creo que no hay una respuesta fácil a esta pregunta. La forma en que realmente puede abordar esta solución depende de sus requisitos. ¿Necesita una solución multiplataforma? ¿Estás usando new / delete o malloc / free (o ambos)? ¿Realmente está buscando solo "fugas" o desea una mejor protección, como la detección de desbordamientos (o desbordamientos) del búfer?
Si está trabajando en el lado de Windows, las bibliotecas de tiempo de ejecución de depuración de MS tienen alguna funcionalidad básica de detección de depuración y, como ya ha señalado otro, hay varios contenedores que pueden incluirse en su fuente para ayudar con la detección de fugas. Encontrar un paquete que pueda funcionar tanto con new / delete como malloc / free obviamente le brinda más flexibilidad.
No sé lo suficiente sobre el lado de Unix para proporcionar ayuda, aunque nuevamente, otros sí.
Pero más allá de la detección de fugas, existe la noción de detectar daños en la memoria a través de desbordamientos (o desbordamientos) del búfer. Creo que este tipo de funcionalidad de depuración es más difícil que la detección de fugas simple. Este tipo de sistema también se complica aún más si está trabajando con objetos C ++ porque las clases polimórficas se pueden eliminar de diversas maneras, lo que provoca trucos para determinar el puntero base verdadero que se está eliminando. No conozco ningún buen sistema "gratuito" que ofrezca una protección decente para los excesos. hemos escrito un sistema (multiplataforma) y nos pareció bastante desafiante.
fuente
Me gustaría ofrecer algo que he usado en el pasado: un verificador de fugas rudimentario que es de nivel fuente y bastante automático. Estoy regalando esto por tres razones:
Tu podrias encontrar esto útil.
Aunque es un poco grosero, no dejo que eso me avergüence.
A pesar de que está vinculado a algunos ganchos win32, eso debería ser fácil de aliviar.
Hay cosas de las que debe tener cuidado al usarlo: no haga nada que deba apoyarse
new
en el código subyacente, tenga cuidado con las advertencias sobre los casos que podría fallar en la parte superior de leakcheck.cpp, tenga en cuenta que si activa en (y arregle cualquier problema con) el código que hace volcados de imágenes, puede generar un archivo enorme.El diseño está diseñado para permitirle activar y desactivar el verificador sin volver a compilar todo lo que incluye su encabezado. Incluya leakcheck.h donde desee rastrear la comprobación y reconstruir una vez. A partir de entonces, compile leakcheck.cpp con o sin LEAKCHECK # definido y luego vuelva a vincularlo para encenderlo y apagarlo. Incluyendo unleakcheck.h lo desactivará localmente en un archivo. Se proporcionan dos macros: CLEARALLOCINFO () evitará informar el mismo archivo y línea de manera inapropiada cuando atraviese el código de asignación que no incluyó leakcheck.h. ALLOCFENCE () simplemente deja caer una línea en el informe generado sin hacer ninguna asignación.
Una vez más, tenga en cuenta que no he usado esto en mucho tiempo y es posible que tenga que trabajar un poco. Lo estoy dejando caer para ilustrar la idea. Si resulta que hay suficiente interés, estaría dispuesto a elaborar un ejemplo, actualizar el código en el proceso y reemplazar el contenido de la siguiente URL con algo más agradable que incluya una lista de colores de sintaxis decente.
Puede encontrarlo aquí: http://www.cse.ucsd.edu/~tkammeye/leakcheck.html
fuente
Para Linux: pruebe Google Perftools
Hay muchas herramientas que hacen aloc / conteo libre similar, los pros de Goolge Perftools:
fuente
La mejor defensa contra fugas es una estructura de programa que minimiza el uso de malloc. Esto no solo es bueno desde una perspectiva de programación, sino que también mejora el rendimiento y la mantenibilidad. No estoy hablando de usar otras cosas en lugar de malloc, sino en términos de reutilizar objetos y mantener pestañas muy explícitas sobre todos los objetos que se pasan, en lugar de asignar de cualquier manera como se acostumbra en idiomas con recolectores de basura. como Java
Por ejemplo, un programa en el que trabajo tiene un montón de objetos de cuadro que representan datos de imagen. Cada objeto de cuadro tiene datos secundarios, que el destructor del cuadro libera. El programa mantiene una lista de todos los marcos asignados, y cuando necesita uno nuevo, verifica una lista de objetos de marco no utilizados para ver si puede reutilizar uno existente en lugar de asignar uno nuevo. En el apagado, simplemente recorre la lista, liberando todo.
fuente
Recomendaría usar Memory Validator de la verificación del software. Esta herramienta demostró ser de inestimable ayuda para ayudarme a rastrear pérdidas de memoria y mejorar la administración de memoria de las aplicaciones en las que estoy trabajando.
Una herramienta muy completa y rápida.
fuente
¿Está contando las asignaciones y liberaciones al interpolar sus propias funciones syscall que registran las llamadas y luego pasan la llamada a la función real?
Esta es la única forma en que puede realizar un seguimiento de las llamadas que se originan en el código que no ha escrito.
Echa un vistazo a la página de manual de ld.so. O ld.so.1 en algunos sistemas.
También haga Google LD_PRELOAD y encontrará algunos artículos interesantes que explican la técnica en www.itworld.com.
fuente
Al menos para MS VC ++, la biblioteca C Runtime tiene varias funciones que he encontrado útiles en el pasado. Consulte la ayuda de MSDN para las
_Crt*
funciones.fuente
El mmgr de Paul Nettle es una herramienta mía favorita desde hace mucho tiempo. Incluya mmgr.h en sus archivos de origen, defina TEST_MEMORY y proporciona un archivo de texto lleno de problemas de memoria que ocurrieron durante la ejecución de su aplicación.
fuente
Pauta general de codificación:
fuente
Las herramientas de depuración de memoria valen su peso en oro, pero a lo largo de los años he descubierto que se pueden usar dos ideas simples para evitar que la mayoría de las pérdidas de memoria / recursos se codifiquen en primer lugar.
Escriba el código de liberación inmediatamente después de escribir el código de adquisición para los recursos que desea asignar. Con este método es más difícil de "olvidar" y, en cierto sentido, obliga a pensar seriamente en el ciclo de vida de los recursos que se utilizan por adelantado en lugar de como un lado.
Use el retorno lo más moderadamente posible. Lo que se asigna solo debe liberarse en un lugar si es posible. El camino condicional entre la adquisición de recursos y la liberación debe diseñarse para que sea lo más simple y obvio posible.
fuente
En la parte superior de esta lista (cuando lo leí) estaba valgrind. Valgrind es excelente si puede reproducir la fuga en un sistema de prueba. Lo he usado con gran éxito.
¿Qué sucede si acaba de notar que el sistema de producción tiene fugas en este momento y no tiene idea de cómo reproducirlo en la prueba? Alguna evidencia de lo que está mal se captura en el estado de ese sistema de producción, y podría ser suficiente para proporcionar una idea de dónde está el problema para que pueda reproducirlo.
Ahí es donde entra en escena el muestreo de Monte Carlo. Lea el artículo del blog de Raymond Chen, "La forma en que el pobre hombre identifica las pérdidas de memoria" y luego revise mi implementación (supone Linux, probado solo en x86 y x86-64)
http://github.com/tialaramex/leakdice/tree/master
fuente
Trabajando en el sistema operativo de teléfonos celulares Motorola, secuestramos la biblioteca de asignación de memoria para observar todas las asignaciones de memoria. Ayudó a encontrar muchos problemas con las asignaciones de memoria. Como la prevención es mejor que el curado, recomendaría usar una herramienta de análisis estático como Klockwork o PC-Lint
fuente
lint
. Tiene muchas comprobaciones específicas de C ++, que afaik splint no tiene. Vea el enlace en la respuesta (que renombré de Lint a PC-Lint).Valgrind es una buena opción para Linux. En MacOS X, puede habilitar la biblioteca MallocDebug que tiene varias opciones para depurar problemas de asignación de memoria (consulte la página de manual de malloc, la sección "MEDIO AMBIENTE" tiene los detalles relevantes). El SDK de OS X también incluye una herramienta llamada MallocDebug (generalmente instalada en / Developer / Applications / Performance Tools /) que puede ayudarlo a monitorear el uso y las fugas.
fuente
Detectar:
CRT de depuración
Evitar:
Punteros inteligentes, boehm GC
fuente
Un buen reemplazo de malloc, calloc y reallloc es rmdebug, es bastante simple de usar. Es mucho más rápido que valgrind, por lo que puede probar su código exhaustivamente. Por supuesto, tiene algunas desventajas, una vez que encuentre una fuga, probablemente todavía necesite usar valgrind para encontrar dónde aparece la fuga y solo puede probar mallocs que hace directamente. Si una lib se filtra porque la usas mal, rmdebug no la encontrará.
http://www.hexco.de/rmdebug/
fuente
La mayoría de los perfiladores de memoria ralentizan mi gran aplicación compleja de Windows hasta el punto en que los resultados son inútiles. Hay una herramienta que funciona bien para encontrar fugas en mi aplicación: UMDH - http://msdn.microsoft.com/en-us/library/ff560206%28VS.85%29.aspx
fuente
Mtrace parece ser el estándar integrado para Linux. Los pasos son:
MALLOC_TRACE = / tmp / mtrace.dat
export MALLOC_TRACE;
mtrace your_prog_exe_name /tmp/mtrace.dat
( primero tuve que instalar el script mtrace perl en mi sistema fedora con yum install glibc_utils )
fuente