哪位大侠精通WINDOWS下内存泄漏诊断方法?程序是VC开发的,代码规模为60万行以上,运行过程中内存占用量过G,这种情况下如何定位内存泄漏?有哪些工具和方法?谢谢!

解决方案 »

  1.   

    memory  profiler试试这个工具
      

  2.   

    微软有一套小工具,里面有一个UMDH.EXE,非常好用。
      

  3.   

    http://www.sizeof.cn/html/2009/107.html
      

  4.   

    Visual C++ 的 C 运行时刻函数库标识模板
    0xCD    已经分配的数据(alloCated Data)
    0xDD    已经释放的数据(Deleted Data)
    0xFD    被保护的数据(Fence Data)Visual C++ 的 C 运行时刻函数库内存块类型标识符
    _NORMAL_BLOCK    由程序直接分配的内存
    _CLIENT_BLOCK    由程序直接分配的内存,可以通过内存调试函数对其拥有特殊控制权
    _CRT_BLOCK       由运行时刻函数库内部分配的内存
    _FREE_BLOCK      已经被释放,但是跟踪仍然被保留下来的内存,这在用户选择了调试堆的选项 _CRTDBG_DELAY_FREE_MEM_DF 以后会出现
    _IGNORE_BLOCK    当使用 _CrtDbgFlag 关闭内存调试操作以后分配的内存Visual C++ 的 C 运行时刻函数库提供的帮助调试内存错误的函数
    _CrtCheckMemory  检查每一个内存块的内部数据结构和守护(guard)字节,以测试其完整性。
    _CrtIsValidHeapPointer 检验指定指针是否存在于本地堆中
    _CrtIsValidPointer 检验给定内存范围对读写操作是否合法
    _CrtIsMemoryBlock 检验给定内存范围是否位于本地堆当中,是否拥有例如 _NORMAL_BLOCK 这样的有效内存块类型标识符(该函数还可以被用以获得分配数目以及进行内存分配的源文件名和行号)用于调试内存泄露的 Visual C++ 的 C 运行时刻函数库中的函数
    _CrtSetBreakAlloc   在给定的分配数目上分配断点,每一块被分配的内存都被指派一个连续的分配号。(查找特定的内存泄露十分有用)
    _CrtDumpMemoryLeaks 判断内存泄露是否发生。如果发生则将本地堆中所有当前分配的内存按照用户可以阅读的方式进行内存映象转储。(在程序结束的时候检测内存泄露十分有用)
    _CrtMemCheckPoint   在 _CrtMemState 结构中产生一个本地堆的当前状态的快照
    _CrtMemDifference   比较两个堆中的断点,将不同之处保存在 _CrtMemState 结构中。如果不同则返真。(检测特殊区域代码的内存泄露十分有用)
    _CrtMemDumpAllObjectsSince将从给定堆断点或者从程序开始分配的内存的所有信息按照用户可以阅读的方式进行内存映象转储
    _CrtMemDumpStatistics 将信息按照用户可以阅读的方式进行内存映象转储到一个 _CrtMemState 结构中。(对于得到被使用的动态内存的全面观察信息来说十分有用)用于一般内存调试的 Visual C++ 的 C 运行时刻函数库中的函数
    _CrtSetDbgFlag      控制内存调试函数的行为
    _CrtSetAllocHook    加裁在内存分配过程中的钩子函数。(对于检测内存使用状况或者模拟内存不足情况十分有用)
    _CrtSetReportHook   加裁进行定制报告处理的函数。
    _CrtSetDumpClient   加裁对用户进行内存映象转储的函数。
    _CrtDoForAllClientObject 对于所有作为用户块进行分配的数据,调用指定的函数
      

  5.   

    ATL 内存调试
    在 #include <AtlCom.h> 之前,定义控制预处理的常量 _ATL_DEBUG_INTERFACES,这样就可以对接口资源泄露进行跟踪(跟踪 AddRef 和 Release)
    INTERFACE LEAK: RefCount = 7, MaxRefCount = 10, {Allocation = 42}
    CMyComClass - Leak
    然后在服务器初始化的时候对 CComModule 对象的 m_nIndexBreakAt 成员变量进行设置
    #define _ATL_DEBUG_INTERFACESBOOL WINAPI DllMain(...)
    {
        if (dwReason == DLL_PROCESS_ATTACH) {
            ...
            _Module.m_nIndexBreakAt = 42; // Set breakpoint to find interface leak
        }
        ...
    }使用调试堆
    必须使用程序的调试版本,连接的是 C 运行时刻函数库的调试版本,必须定义 _DEBUG,这样调试堆版本的 new 和 delete 才会被调用。
    调试堆选项
    _CRTDBG_ALLOC_MEME_DF,启动堆分配检查
    _CRTDBG_DELAY_FREE_MEM_DF,阻止内存被真正释放
    _CRTDBG_CHECK_ALWAYS_DF,每次内存分配和释放都调用 _CrtCheckMemory
    _CRTDBG_CHECK_CRT_DF,一般不使用
    _CRTDBG_LEAK_CHECK_DF,在程序结束时调用 _CrtDumpMemoryLeaks
    推荐总是使用 _CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF,仅仅在调试内存错误时才用 _CRTDBG_CHECK_ALWAYS_DF 和 _CRTDBG_DELAY_FREE_MEM_DF,显示内存泄露
    #define _CRTDBG_MAP_ALLOC 在所有头文件之前,
    在 cpp 文件中,加上
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif查看 Windows 内存地址
    Windows 进程一般放在 0x00400000 的地址,0x00400000 是所有版本的 Windows 能使用的最低地址,进程实例句柄的值总是和它的基地址相同,
    所有未被初始化的自动变量都会设上 0xCCCCCCCC,
      

  6.   

    Windows 2000 的虚拟地址空间的使用
    0x00030000 ~ 0x0012FFFF 线程栈
    0x00130000 ~ 0x003FFFFF 堆(有时堆位于此处)
    0x00400000 ~ 0x005FFFFF 可执行代码
    0x00600000 ~ 0x0FFFFFFF 堆(有时堆位于此处)
    0x10000000 ~ 0x5FFFFFFF App Dlls, Msvcrt.dll, Mfc42.dll
    0x77000000 ~ 0xFFFFFFFF Advapi32.dll,...通过设置数据断点,在对 0xCDCDCDCD,0xCCCCCCCC,0xDDDDDDDD 等地址修改时,调试器会提醒你,写非合法数据
    调试比较难的内存破坏问题时,可以试试 _CRTDBG_CHECK_ALWAYS_DF 和 _CRTDBG_DELAY_FREE_MEM_DF,当类需要析构函数或者复制构造函数或者赋值操作符时,它同时需要这三个,否则可能导致内存破坏和泄露,用分配号定位内存泄露
    _CrtSetBreakAlloc(27)
    Watch 窗口 {,,msvcrtd.dll}_CrtSetBreakAlloc(27)使用内存检查点
    void LeakyFunction()
    {
        _CrtMemState oldState, newState, stateDiff;
        _CrtMemCheckPoint(&oldState);
        {
        ...
        }
        _CrtMemCheckPoint(&newState);
        if (_CrtMemeDifference(&stateDiff, &oldState, &newState)) {
            _CrtMemDumpStatistics(&stateDiff);
            _CrtMemDumpAllObjectsSince(&oldState);
        }
    }
    使用 _CRTDBG_DELAY_FREE_MEM_DF 调试堆选项防止 _CrtMemDumpAllObjectsSince 导出错误的结果在删除图形设备接口对象前,一定确定它们没有被任何有效的设备上下文选中
    在 Windows 2000 里发现资源泄露是最简单方法是运行性能监视工具,监视程序的私有空间和句柄数随时间的变化,如果私有空间或者句柄数据持续增长,就出现了内存泄露
    函数的返回值是通过 EAX 传递的,
      

  7.   

    谢谢各位!umdh我正在用,手工作业比较多点,不过不错
    GDI泄漏有什么好方法查么?
      

  8.   

    好像有个bounds checker的
    对内存方面的东西都挺有效
      

  9.   

    boundschecher是个好东西,但只能应付小程序看来只能大量手工作业,谢谢各位,散分结贴