内存泄漏诊断方法 哪位大侠精通WINDOWS下内存泄漏诊断方法?程序是VC开发的,代码规模为60万行以上,运行过程中内存占用量过G,这种情况下如何定位内存泄漏?有哪些工具和方法?谢谢! 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 memory profiler试试这个工具 微软有一套小工具,里面有一个UMDH.EXE,非常好用。 http://www.sizeof.cn/html/2009/107.html 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 对于所有作为用户块进行分配的数据,调用指定的函数 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_FILEstatic char THIS_FILE[] = __FILE__;#endif查看 Windows 内存地址Windows 进程一般放在 0x00400000 的地址,0x00400000 是所有版本的 Windows 能使用的最低地址,进程实例句柄的值总是和它的基地址相同,所有未被初始化的自动变量都会设上 0xCCCCCCCC, Windows 2000 的虚拟地址空间的使用0x00030000 ~ 0x0012FFFF 线程栈0x00130000 ~ 0x003FFFFF 堆(有时堆位于此处)0x00400000 ~ 0x005FFFFF 可执行代码0x00600000 ~ 0x0FFFFFFF 堆(有时堆位于此处)0x10000000 ~ 0x5FFFFFFF App Dlls, Msvcrt.dll, Mfc42.dll0x77000000 ~ 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 传递的, 谢谢各位!umdh我正在用,手工作业比较多点,不过不错GDI泄漏有什么好方法查么? 好像有个bounds checker的对内存方面的东西都挺有效 boundschecher是个好东西,但只能应付小程序看来只能大量手工作业,谢谢各位,散分结贴 Serv-U和LeapFTP win2003-64bit如何使用DLL? 关于多工程调用的问题?? 无标题栏对话框重绘标题栏XP,VISTA兼容性。 单件模式下返回静态对象的函数体被放在头文件中会不回产生什么不良后果吗? 数据发送到主机时,怎样编写接收程序? 为什么客户区一片黑? 关于资源ID号的问题 考一下程序员的智商及德商 有没有名实现nbtstat命令功能的函数或类? 请问fopen_s的使用 如何清除用Polygon()生成的图形?
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 对于所有作为用户块进行分配的数据,调用指定的函数
在 #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,
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 传递的,
GDI泄漏有什么好方法查么?
对内存方面的东西都挺有效