代码之家  ›  专栏  ›  技术社区  ›  Patrick

如何使用应用程序验证器查找内存泄漏

  •  9
  • Patrick  · 技术社区  · 15 年前

    我想使用标准实用程序在应用程序中查找内存泄漏。 以前我使用自己的内存分配器,但其他人(是的,你是Alienfluid)建议使用Microsoft的应用程序验证程序,但我似乎无法让它报告我的泄漏。 我有以下简单的应用程序:

    #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;
    }
    

    此测试显然包含内存泄漏:p2是新的,但没有删除。

    我使用以下命令行生成可执行文件:

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

    我下载了应用程序验证程序(4.0.0665)并启用了所有检查。

    如果我现在运行测试应用程序,我可以在应用程序验证程序中看到它的日志,但是我看不到内存泄漏。

    问题:

    • 为什么应用程序验证程序不报告泄漏?
    • 或者应用程序验证程序不是真的打算查找泄漏吗?
    • 如果没有其他工具可用于在应用程序结束时清楚地报告泄漏(即不通过定期快照并进行比较,因为在使用1GB或更高容量的应用程序中是不可能的),包括分配位置的调用堆栈(因此不是CRT结束时的简单泄漏报告)。

    如果我找不到一个合适的实用程序,我仍然需要依靠我自己的内存管理器(它做得很好)。

    6 回复  |  直到 11 年前
        1
  •  4
  •   Scott 混合理论 Alex F    11 年前

    CRT内存泄漏检测(无堆栈跟踪):

    // debug_new.h
    #pragma once
    
    #include "crtdbg.h"
    
    #ifdef _DEBUG
    #ifndef DEBUG_NEW
    #define DEBUG_NEW   new( _NORMAL_BLOCK, __FILE__, __LINE__)
    #endif
    #endif
    

    所有.CPP文件:

    #include "debug_new.h"
    
    ...
    
    // After all other include lines:
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    ...
    

    在程序初始化代码中写入一次:

    _CrtSetDbgFlag( _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
    

    在MFC中,所有这些都已在MFC头中实现。您只需要确保每个cpp文件都包含以下行:

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    

    限制:这只捕获“新”内存泄漏,不会捕获由其他函数(如malloc)引起的所有泄漏。

    不要在.h文件中进行任何分配-这些文件将在没有源代码行的情况下打印,因为调试\新建是在所有\包括行之后定义的。

        2
  •  4
  •   Wanderley Caloni    14 年前

    应用程序验证程序只捕获DLL中的泄漏。尝试阅读“泄漏”复选框中的工具提示。它就是这么说的。

        3
  •  1
  •   Alienfluid    15 年前

    我有一种感觉,应用程序验证器会对退出路径进行特殊处理,并且不会将其标记为泄漏——毕竟,整个进程堆在进程退出时是空闲的。

    尝试编写另一个示例,在该示例中再次初始化同一指针——基本上会丢失对前一个分配的引用。这当然应该被标记出来。让我知道结果。

    此外,AppVerifier(如果您启用了所有选项)还应捕获缓冲区溢出、下溢、写入标记为ro的堆栈位置等。

        4
  •  1
  •   StarPilot    13 年前

    来自软件验证的内存验证器将捕获内存泄漏,并显示来自泄漏分配的完整调用堆栈。虽然它是一个商业产品,但它有一个试用期,这样程序员就可以试用它,看看它对他们来说是否值得。

        5
  •  0
  •   anon    15 年前

    最简单的解决方案是 首先不要写泄漏或缓冲区溢出 -事后发现它们真的是浪费精力。在我自己的代码中,多年来我在这些领域没有遇到任何问题。为什么?因为我使用C++提供的机制来避免它们。例如:

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

    应该是:

    shared_ptr <X>  p1 = new X();
    

    你不再担心P1泄漏。更好的是,完全不要使用动态分配:

    X x1;
    

    对于缓冲区溢出,总是使用std::string等类型,这些类型在输入时会增长,或者如果不增长,则会检测到可能的溢出并警告您。

    我不是在吹嘘我在避免内存泄漏方面的能力-这些东西确实有效,并且允许你继续进行调试 商业 代码的逻辑。

        6
  •  0
  •   philipvr    13 年前

    Visual Leak Detector (v2.2)比CRT调试库更有用,因为它将显示用于内存分配的完整调用堆栈导致了泄漏。