2010-06-02 12 views
9

Quiero encontrar pérdidas de memoria en mi aplicación utilizando utilidades estándar. Anteriormente utilicé mi propio asignador de memoria, pero otras personas (sí, usted AlienFluid) sugirieron usar el verificador de aplicaciones de Microsoft, pero parece que no puedo informar de mis filtraciones. Tengo el siguiente aplicación sencilla:Cómo usar Application Verifier para encontrar fugas de memoria

#include <iostream> 
#include <conio.h> 

class X 
    { 
    public: 
     X::X() : m_value(123) {} 
    private: 
     int m_value; 
    }; 

void main() 
{ 
X *p1 = 0; 
X *p2 = 0; 
X *p3 = 0; 

p1 = new X(); 
p2 = new X(); 
p3 = new X(); 
delete p1; 
delete p3; 
} 

Esta prueba claramente contiene una pérdida de memoria: P2 es new'd pero no eliminado.

construyo el ejecutable usando las siguientes líneas de comandos:

cl /c /EHsc /Zi /Od /MDd test.cpp 
link /debug test.obj 

He descargado comprobador de aplicaciones (4.0.0665) y habilitar todos los controles.

Si ahora ejecuto mi aplicación de prueba, puedo ver un registro de ello en Application Verifier, pero no veo la pérdida de memoria.

Preguntas:

  • ¿Por qué no informan comprobador de aplicaciones de una fuga?
  • ¿O no es Application Verifier realmente destinado a encontrar fugas?
  • Si no están disponibles otras herramientas para informar claramente las fugas al final de la aplicación (es decir, no tomando instantáneas regulares y comparándolas, ya que esto no es posible en una aplicación que toma 1GB o más), incluida la llamada pila del lugar de asignación (por lo que no es el simple informe de fugas al final de la CRT)

Si no encuentro una utilidad decente, todavía tengo que confiar en mi propio administrador de memoria (que lo hace perfectamente).

+0

Este es el problema con estas herramientas: hacen todo menos lo que realmente necesitamos ... ¿La detección de filtraciones de memoria CRT está bien para usted, incluido el lugar de asignación en el código, pero sin la pila de llamadas? En este caso, solo necesita redefinir el nuevo operador y activar el volcado de pérdidas de memoria. –

+1

El problema es que tengo un asignador de memoria perfectamente autodirigido que funciona bastante rápido, registra todas las asignaciones de memoria, incluidas las pilas de llamadas, las filtraciones de informes (incluida la pila de llamadas) al final de la aplicación, comprueba si hay desbordamientos/subdesbordamientos de búfer. .., PERO todos (en StackOverflow) parecen indicar que NO DEBES escribir tu propio administrador de memoria ya que el estándar de CRT/Windows es lo suficientemente bueno, y hay suficientes utilidades para encontrar pérdidas de memoria, sobrescrituras, ... Sin embargo, parece que no puedo hacer que funcionen. – Patrick

+1

También creo que la detección de fugas de memoria no es una razón para escribir su propio asignador de memoria. CRT ofrece todo, excepto el seguimiento de la pila: si es interesante, puedo publicar el código. –

Respuesta

4

memoria CRT se escapa de detección (sin seguimiento de la pila):

 
// debug_new.h 
#pragma once 

#include "crtdbg.h" 

#ifdef _DEBUG 
#ifndef DEBUG_NEW 
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) 
#endif 
#endif 

Todos los archivos .cpp:

 
#include "debug_new.h" 

... 

// After all other include lines: 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#endif 

... 

escribir esta vez en el código de inicialización del programa:

_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF); 

En MFC, todo esto ya está implementado en los encabezados de MFC. Sólo tiene que asegurarse de que todos los archivos CPP contiene estas líneas:

 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#endif 

Restricciones: Esto llama solamente "nuevos" pérdidas de memoria, todas las fugas causadas por otros funciones, como malloc, no están atrapados.

No haga asignaciones dentro de los archivos .h; se imprimirán sin líneas fuente, porque DEBUG_NEW se define después de todas las líneas #include.

+1

Este truco no funciona para malloc/free. Uno de los archivos de inclusión de CRT hace algo similar con MALLOC y FREE (#define DEBUG_FREE gratis o algo así), y esto da problemas con las clases que tienen un método llamado free (por ejemplo, en Qt). Además, esto también escribe las pérdidas de memoria, pero sin pilas de llamadas, y realmente necesito las pilas de llamadas. – Patrick

1

La solución más simple es para no escribir las filtraciones o los desbordamientos de la memoria intermedia en primer lugar - detectarlos después del evento es realmente una pérdida de esfuerzo. En mi propio código, durante años he tenido cero problemas en estas áreas. ¿Por qué? Porque utilizo los mecanismos que proporciona C++ para evitarlos.Por ejemplo:

X *p1 = 0; 
p1 = new X(); 

debería ser:

shared_ptr <X> p1 = new X(); 

y ya no preocuparse por fugas p1. Mejor aún, no utilice la asignación dinámica en todo:

X x1; 

Para desbordamientos de búfer, utilice siempre tipos como std :: string que crecerán en la entrada, o si no crecen detectará la posible desbordamiento y advertir tú.

No estoy haciendo alarde de mi destreza en evitar pérdidas de memoria - esto realmente funciona, y le permite seguir adelante con la tarea mucho más difícil de depurar el negocio lógica de su código.

+3

Muchas almas desafortunadas tienen que lidiar con código heredado (cosas desagradables c no probadas) y no pueden permitirse reescribir todo. – Sascha

+1

La pregunta requiere herramientas para detectar fugas de memoria y la respuesta comienza con "_detectarlas después de que el evento es realmente una pérdida de esfuerzo_". Lo mismo podría decirse de la última declaración "continúen con la tarea mucho más difícil de depurar la lógica comercial de su código": ¿por qué no escribir código que no necesita depuración de su lógica comercial? Claramente, el ejemplo del PO se ideó para demostrar un caso de código de fuga y era un registro de preguntas. cómo detectarlo Por supuesto, es trivial corregir el código. –

+2

La respuesta es completamente ajena al mundo real, donde hay pérdidas de memoria y es necesario eliminarlas. Como dijo @Sascha, una cosa es escribir un código nuevo y otra cosa es mantener el código existente. –

1

Tengo la sensación de que el verificador de aplicaciones presenta casos especiales en la ruta de salida y no los señala como fugas; después de todo, todo el proceso está libre al salir del proceso.

Intente escribir otra muestra en la que inicialice el mismo puntero nuevamente, básicamente perderá la referencia a la asignación anterior. Eso ciertamente debería ser marcado. Déjame saber los resultados.

Además, AppVerifier (si tiene todas las opciones habilitadas) también debe coger desbordamientos de búfer, underflow, escribiendo para apilar los lugares marcados RO etc.

+0

BTW, también pruebe la utilidad "Global Flags" que viene con las herramientas de depuración para Windows en el SDK de Windows. Tiene un montón de opciones para el etiquetado de pila, etc. y es posible que sea lo que necesita. – Alienfluid

+1

Intenté configurar el puntero a 0. Nada informado en el Verificador de aplicación. Se intentó usar GFLAGS para habilitar todos los indicadores relacionados con la memoria. Nada informado. Parece que simplemente es imposible obtener pérdidas de memoria al salir (a excepción de los informes de fuga mínimos en el CRT). Parece que tengo que mantener mi propio administrador de memoria. – Patrick

4

comprobador de aplicaciones solo detecta fugas en archivos DLL. Intente leer la información sobre herramientas en la casilla de verificación de fugas. Eso es lo que dice.

0

Visual Leak Detector (v2.2) es más útil que la biblioteca de depuración CRT porque mostrará que la pila de llamadas utilizada para la asignación de memoria ha provocado la fuga.

+0

es bastante difícil trabajar con VLD cuando se usan singletones C++ –

1

El Validador de memoria de Verificación de software detectará fugas de memoria y mostrará la pila de llamadas completa de la asignación de fugas. Si bien es un producto comercial, tiene un período de prueba para que los programadores puedan probarlo y ver si les vale el precio.

Cuestiones relacionadas