请问,在mfc中如何确定内存泄漏的变量~?

jiaocha 2010-01-27 11:46:44
如题,谢谢`~
...全文
1644 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
e513479333 2010-06-11
  • 打赏
  • 举报
回复
_CrtDumpMemoryLeaks();

函数需要在最后执行才准确,正常情况下MFC对象还没有析构,会被记录为空间未释放

新建一个MFC程序都回提示内存泄露
evan369 2010-05-15
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 c_s0001 的回复:]
如需要阅读该回复,请登录或注册CSDN!
[/Quote]

登陆了也看不到啊???
sxgxd1 2010-05-04
  • 打赏
  • 举报
回复
MFC 的内存泄漏,看看
青稞 2010-01-28
  • 打赏
  • 举报
回复
学习下..顶起..呵呵..
ls2141 2010-01-28
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 icyplayer 的回复:]
检测内存泄漏的主要工具是调试器和 CRT 调试堆函数。若要启用调试堆函数,请在程序中包括以下语句:

#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
注意 #include 语句必须采用上文所示顺序。如果更改了顺序,所使用的函数可能无法正确工作。

通过包括 crtdbg.h,将 malloc 和 free 函数映射到其“Debug”版本_malloc_dbg 和_free_dbg,这些函数将跟踪内存分配和释放。此映射只在调试版本(在其中定义了 _DEBUG)中发生。发布版本使用普通的 malloc 和 free 函数。

#define 语句将 CRT 堆函数的基版本映射到对应的“Debug”版本。并非绝对需要该语句,但如果没有该语句,内存泄漏转储包含的有用信息将较少。

在添加了上面所示语句之后,可以通过在程序中包括以下语句来转储内存泄漏信息:
_CrtDumpMemoryLeaks();
当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在“输出”窗口中显示内存泄漏信息。内存泄漏信息如下所示:
Detected memory leaks!

Dumping objects ->

C:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20) : {18} normal block at 0x00780E80, 64 bytes long.

Data: <        > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
如果不使用 #define _CRTDBG_MAP_ALLOC 语句,内存泄漏转储如下所示: Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
未定义 _CRTDBG_MAP_ALLOC 时,所显示的会是:

内存分配编号(在大括号内)。
块类型(普通、客户端或 CRT)。
十六进制形式的内存位置。
以字节为单位的块大小。
前 16 字节的内容(亦为十六进制)。
定义了 _CRTDBG_MAP_ALLOC 时,还会显示在其中分配泄漏的内存的文件。文件名后括号中的数字(本示例中为 20)是该文件内的行号。

转到源文件中分配内存的行

在"输出"窗口中双击包含文件名和行号的行。
-或-

在"输出"窗口中选择包含文件名和行号的行,然后按 F4 键。

_CrtSetDbgFlag
如果程序总在同一位置退出,则调用 _CrtDumpMemoryLeaks 足够方便,但如果程序可以从多个位置退出该怎么办呢?不要在每个可能的出口放置一个对 _CrtDumpMemoryLeaks 的调用,可以在程序开始包括以下调用:

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
该语句在程序退出时自动调用 _CrtDumpMemoryLeaks。必须同时设置 _CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF 两个位域,如上所示。

说明
在VC++6.0的环境下,不再需要额外的添加

#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
只需要按F5,在调试状态下运行,程序退出后在"输出窗口"可以看到有无内存泄露。如果出现

Detected memory leaks!
Dumping objects ->
就有内存泄露。

确定内存泄露的地方
根据内存泄露的报告,有两种消除的方法:

第一种比较简单,就是已经把内存泄露映射到源文件的,可以直接在"输出"窗口中双击包含文件名和行号的行。例如

Detected memory leaks!
Dumping objects ->
C:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20) : {18} normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
C:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20)
就是源文件名称和行号。

第二种比较麻烦,就是不能映射到源文件的,只有内存分配块号。

Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
  这种情况我采用一种"试探法"。由于内存分配的块号不是固定不变的,而是每次运行都是变化的,所以跟踪起来很麻烦。但是我发现虽然内存分配的块号是变化的,但是变化的块号却总是那几个,也就是说多运行几次,内存分配的块号很可能会重复。因此这就是"试探法"的基础。

先在调试状态下运行几次程序,观察内存分配的块号是哪几个值;
选择出现次数最多的块号来设断点,在代码中设置内存分配断点: 添加如下一行(对于第 18 个内存分配): _crtBreakAlloc = 18;
或者,可以使用具有同样效果的 _CrtSetBreakAlloc 函数: _CrtSetBreakAlloc(18);

在调试状态下运行序,在断点停下时,打开"调用堆栈"窗口,找到对应的源代码处;

退出程序,观察"输出窗口"的内存泄露报告,看实际内存分配的块号是不是和预设值相同,如果相同,就找到了;如果不同,就重复步骤3,直到相同。

最后就是根据具体情况,在适当的位置释放所分配的内存。
[/Quote]
他的资料好多啊
marrco2005 2010-01-27
  • 打赏
  • 举报
回复
自己new 出来的内存泄露可以定位
双击一下内存泄露的信息,就可以了
冻结 2010-01-27
  • 打赏
  • 举报
回复
如果只是MFC,没办法,不然怎么叫内存泄露呢。

除非你自己做一些其他的工作。
来管理内存。
jize00 2010-01-27
  • 打赏
  • 举报
回复
像下面这样写,然后在Debug模式下就可以在输出窗口看到内存泄漏的地方,双击可以定位

#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define DEBUG_NEW new(_CLIENT_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif

void main(void)
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
.......// your code
_CrtDumpMemoryLeaks();
}
rainsly 2010-01-27
  • 打赏
  • 举报
回复
使用
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
即可
xwsn007 2010-01-27
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 robertbaker 的回复:]
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_INTERFACES

BOOL 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,

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 传递的,

[/Quote]

强,学习了
你妹的特盗不 2010-01-27
  • 打赏
  • 举报
回复
最好的办法就是,项目中查找所有new 创建的东西,还有指针之类的东西,这些是需要手动去释放的
打开了,要关闭,习惯问题
你妹的特盗不 2010-01-27
  • 打赏
  • 举报
回复
为这问题我检查我程序好久,实在找不出哪里会有这问题了,新建个报一样的错误。。。。。
你妹的特盗不 2010-01-27
  • 打赏
  • 举报
回复
LS的,你们的利器也太夸张了吧,我就用vs2008新建一个dialog对话框的程序,啥都没动,在stdafx.h
#include "vld.h"
在debug下面运行程序,然后退出,都说有内存漏露

'tt.exe': Loaded 'D:\My Documents\Visual Studio 2008\Projects\tt\Debug\tt.exe', Symbols loaded.
'tt.exe': Loaded 'C:\WINDOWS\system32\ntdll.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\kernel32.dll'
'tt.exe': Loaded 'C:\Program Files\Visual Leak Detector\bin\vld.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\advapi32.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\rpcrt4.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\secur32.dll'
'tt.exe': Loaded 'C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.4053_x-ww_e6967989\msvcr80.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\msvcrt.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\user32.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\gdi32.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\comdlg32.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\shlwapi.dll'
'tt.exe': Loaded 'C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2982_x-ww_ac3f9c03\comctl32.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\shell32.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\winspool.drv'
'tt.exe': Loaded 'C:\WINDOWS\system32\oledlg.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\ole32.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\oleaut32.dll'
'tt.exe': Loaded 'C:\Program Files\Visual Leak Detector\bin\dbghelp.dll'
Visual Leak Detector Version 1.9d installed.
'tt.exe': Loaded 'C:\WINDOWS\system32\imm32.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\lpk.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\usp10.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\uxtheme.dll'
'tt.exe': Loaded 'C:\Program Files\360\360safe\safemon\safemon.dll', Binary was not built with debug information.
'tt.exe': Loaded 'C:\WINDOWS\system32\msimg32.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\wininet.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\crypt32.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\msasn1.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\psapi.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\version.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\ws2_32.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\ws2help.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\urlmon.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\msctf.dll'
'tt.exe': Loaded 'C:\WINDOWS\system32\msctfime.ime'
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 59 at 0x00B29F58: 40 bytes ----------
Call Stack:
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp (141): CAfxStringMgr::Allocate
c:\program files\microsoft visual studio 9.0\vc\atlmfc\include\atlsimpstr.h (775): ATL::CSimpleStringT<wchar_t,0>::Fork
c:\program files\microsoft visual studio 9.0\vc\atlmfc\include\atlsimpstr.h (812): ATL::CSimpleStringT<wchar_t,0>::PrepareWrite2
c:\program files\microsoft visual studio 9.0\vc\atlmfc\include\atlsimpstr.h (801): ATL::CSimpleStringT<wchar_t,0>::PrepareWrite
c:\program files\microsoft visual studio 9.0\vc\atlmfc\include\atlsimpstr.h (524): ATL::CSimpleStringT<wchar_t,0>::GetBuffer
f:\dd\vctools\vc7libs\ship\atlmfc\include\atlsimpstr.h (639): ATL::CSimpleStringT<wchar_t,0>::SetString
f:\dd\vctools\vc7libs\ship\atlmfc\include\atlsimpstr.h (616): ATL::CSimpleStringT<wchar_t,0>::SetString
f:\dd\vctools\vc7libs\ship\atlmfc\include\atlsimpstr.h (332): ATL::CSimpleStringT<wchar_t,0>::operator=
f:\dd\vctools\vc7libs\ship\atlmfc\include\cstringt.h (1033): ATL::CStringT<wchar_t,StrTraitMFC<wchar_t,ATL::ChTraitsCRT<wchar_t> > >::operator=
f:\dd\vctools\vc7libs\ship\atlmfc\include\cstringt.h (810): ATL::CStringT<wchar_t,StrTraitMFC<wchar_t,ATL::ChTraitsCRT<wchar_t> > >::CStringT<wchar_t,StrTraitMFC<wchar_t,ATL::ChTraitsCRT<wchar_t> > >
f:\dd\vctools\vc7libs\ship\atlmfc\include\afxcomctl32.h (506): CShellWrapper::CShellWrapper
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\afxstate.cpp (190): AFX_MODULE_STATE::AFX_MODULE_STATE
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\afxstate.cpp (429): _AFX_BASE_MODULE_STATE::_AFX_BASE_MODULE_STATE
f:\dd\vctools\vc7libs\ship\atlmfc\include\afxtls_.h (227): CProcessLocal<_AFX_BASE_MODULE_STATE>::CreateObject
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\afxtls.cpp (464): CProcessLocalObject::GetData
f:\dd\vctools\vc7libs\ship\atlmfc\include\afxtls_.h (213): CProcessLocal<_AFX_BASE_MODULE_STATE>::GetData
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\afxstate.cpp (467): AfxGetModuleState
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\appmodul.cpp (37): AfxInitialize
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\appmodul.cpp (69): `dynamic initializer for '_afxInitAppState''
f:\dd\vctools\crt_bld\self_x86\crt\src\crt0dat.c (903): _initterm
f:\dd\vctools\crt_bld\self_x86\crt\src\crt0dat.c (307): _cinit
f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c (249): __tmainCRTStartup
f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c (182): wWinMainCRTStartup
0x7C816FE7 (File and line number not available): RegisterWaitForInputIdle
Data:
B4 94 6F 00 0B 00 00 00 0B 00 00 00 01 00 00 00 ..o..... ........
73 00 68 00 65 00 6C 00 6C 00 33 00 32 00 2E 00 s.h.e.l. l.3.2...
64 00 6C 00 6C 00 00 00 d.l.l... ........

Visual Leak Detector detected 1 memory leak.
Visual Leak Detector is now exiting.
The program '[5228] tt.exe: Native' has exited with code 2 (0x2).
IcyPlayer 2010-01-27
  • 打赏
  • 举报
回复
检测内存泄漏的主要工具是调试器和 CRT 调试堆函数。若要启用调试堆函数,请在程序中包括以下语句:

#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
注意 #include 语句必须采用上文所示顺序。如果更改了顺序,所使用的函数可能无法正确工作。

通过包括 crtdbg.h,将 malloc 和 free 函数映射到其“Debug”版本_malloc_dbg 和_free_dbg,这些函数将跟踪内存分配和释放。此映射只在调试版本(在其中定义了 _DEBUG)中发生。发布版本使用普通的 malloc 和 free 函数。

#define 语句将 CRT 堆函数的基版本映射到对应的“Debug”版本。并非绝对需要该语句,但如果没有该语句,内存泄漏转储包含的有用信息将较少。

在添加了上面所示语句之后,可以通过在程序中包括以下语句来转储内存泄漏信息:
_CrtDumpMemoryLeaks();
当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在“输出”窗口中显示内存泄漏信息。内存泄漏信息如下所示:
Detected memory leaks!

Dumping objects ->

C:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20) : {18} normal block at 0x00780E80, 64 bytes long.

Data: <        > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
如果不使用 #define _CRTDBG_MAP_ALLOC 语句,内存泄漏转储如下所示: Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
未定义 _CRTDBG_MAP_ALLOC 时,所显示的会是:

内存分配编号(在大括号内)。
块类型(普通、客户端或 CRT)。
十六进制形式的内存位置。
以字节为单位的块大小。
前 16 字节的内容(亦为十六进制)。
定义了 _CRTDBG_MAP_ALLOC 时,还会显示在其中分配泄漏的内存的文件。文件名后括号中的数字(本示例中为 20)是该文件内的行号。

转到源文件中分配内存的行

在"输出"窗口中双击包含文件名和行号的行。
-或-

在"输出"窗口中选择包含文件名和行号的行,然后按 F4 键。

_CrtSetDbgFlag
如果程序总在同一位置退出,则调用 _CrtDumpMemoryLeaks 足够方便,但如果程序可以从多个位置退出该怎么办呢?不要在每个可能的出口放置一个对 _CrtDumpMemoryLeaks 的调用,可以在程序开始包括以下调用:

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
该语句在程序退出时自动调用 _CrtDumpMemoryLeaks。必须同时设置 _CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF 两个位域,如上所示。

说明
在VC++6.0的环境下,不再需要额外的添加

#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
只需要按F5,在调试状态下运行,程序退出后在"输出窗口"可以看到有无内存泄露。如果出现

Detected memory leaks!
Dumping objects ->
就有内存泄露。

确定内存泄露的地方
根据内存泄露的报告,有两种消除的方法:

第一种比较简单,就是已经把内存泄露映射到源文件的,可以直接在"输出"窗口中双击包含文件名和行号的行。例如

Detected memory leaks!
Dumping objects ->
C:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20) : {18} normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
C:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20)
就是源文件名称和行号。

第二种比较麻烦,就是不能映射到源文件的,只有内存分配块号。

Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
  这种情况我采用一种"试探法"。由于内存分配的块号不是固定不变的,而是每次运行都是变化的,所以跟踪起来很麻烦。但是我发现虽然内存分配的块号是变化的,但是变化的块号却总是那几个,也就是说多运行几次,内存分配的块号很可能会重复。因此这就是"试探法"的基础。

先在调试状态下运行几次程序,观察内存分配的块号是哪几个值;
选择出现次数最多的块号来设断点,在代码中设置内存分配断点: 添加如下一行(对于第 18 个内存分配): _crtBreakAlloc = 18;
或者,可以使用具有同样效果的 _CrtSetBreakAlloc 函数: _CrtSetBreakAlloc(18);

在调试状态下运行序,在断点停下时,打开"调用堆栈"窗口,找到对应的源代码处;

退出程序,观察"输出窗口"的内存泄露报告,看实际内存分配的块号是不是和预设值相同,如果相同,就找到了;如果不同,就重复步骤3,直到相同。

最后就是根据具体情况,在适当的位置释放所分配的内存。
dong364 2010-01-27
  • 打赏
  • 举报
回复
mfc的程序自动可以定位
c_s0001 2010-01-27
  • 打赏
  • 举报
回复
//[内存泄露]查杀之利器
[内存泄露]查杀之利器---------Visual Leak Detector
[VCKBASE网友原创]
废话不多说, 如果您正在为内存泄露而烦恼, 就试此工具.

1.仅适用于VC (可能只适用于VC6/7/8);
2.适用于C/C++;
3.最重要的是...它是免费的.

安装:

下载地址:http://www.codeproject.com/tools/visualleakdetector.asp

解压后,应该有:
vld.h
vldapi.h

vld.lib
vldmt.lib
vldmtdll.lib

dbghelp.dll

共6个文件,分别复制到VC的相应目录(include&lib&bin)
Microsoft Visual Studio/VC/include
Microsoft Visual Studio/VC/lib
Microsoft Visual Studio/VC/bin


使用:


#include <vld.h>//仅此一句,即可检查内存泄露

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
char* s = new char[20];
strcpy(s, "hello,world.");

system("pause");
return 0;
}


MFC的朋友,你直接在stdafx.h里,加入一行代码即可:
#include <vld.h>

如果您不知道哪里如何查看结果:
1.运行程序;
2.关闭程序;
3.查看VC编辑器下方的"输出"框.

内容如此这般:
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 55 at 0x003B7C98: 20 bytes ----------
Call Stack:
d:\work\code\vld_test\vld_test\main.cpp (9): main
f:\rtm\vctools\crt_bld\self_x86\crt\src\crtexe.c (586): __tmainCRTStartup
f:\rtm\vctools\crt_bld\self_x86\crt\src\crtexe.c (403): mainCRTStartup
0x7C817077 (File and line number not available): RegisterWaitForInputIdle
Data:
68 65 6C 6C 6F 2C 77 6F 72 6C 64 2E 00 CD CD CD hello,wo rld.....
CD CD CD CD ........ ........

Visual Leak Detector detected 1 memory leak.


参考:
http://blog.csdn.net/niitlcj/archive/2007/11/08/1874337.aspx


//////////////////////////////////////////
内存泄露检测工具 -- Visual Leak Detector 收藏
初识Visual Leak Detector
灵活自由是C/C++语言的一大特色,而这也为C/C++程 序员出了一个难题。当程序越来越复杂时,内存的管理也会变得越加复杂,稍有不慎就会出现内存问题。内存泄漏是最常见的内存问题之一。内存泄漏如果不是很严 重,在短时间内对程序不会有太大的影响,这也使得内存泄漏问题有很强的隐蔽性,不容易被发现。然而不管内存泄漏多么轻微,当程序长时间运行时,其破坏力是 惊人的,从性能下降到内存耗尽,甚至会影响到其他程序的正常运行。另外内存问题的一个共同特点是,内存问题本身并不会有很明显的现象,当有异常现象出现时 已时过境迁,其现场已非出现问题时的现场了,这给调试内存问题带来了很大的难度。

Visual Leak Detector是一款用于Visual C++的免费的内存泄露检测工具。可以在http://www.codeproject.com/tools/visualleakdetector.asp 下载到。相比较其它的内存泄露检测工具,它在检测到内存泄漏的同时,还具有如下特点:
1、 可以得到内存泄漏点的调用堆栈,如果可以的话,还可以得到其所在文件及行号;
2、 可以得到泄露内存的完整数据;
3、 可以设置内存泄露报告的级别;
4、 它是一个已经打包的lib,使用时无须编译它的源代码。而对于使用者自己的代码,也只需要做很小的改动;
5、 他的源代码使用GNU许可发布,并有详尽的文档及注释。对于想深入了解堆内存管理的读者,是一个不错的选择。

可见,从使用角度来讲,Visual Leak Detector简单易用,对于使用者自己的代码,唯一的修改是#include Visual Leak Detector的头文件后正常运行自己的程序,就可以发现内存问题。从研究的角度来讲,如果深入Visual Leak Detector源代码,可以学习到堆内存分配与释放的原理、内存泄漏检测的原理及内存操作的常用技巧等。
本文首先将介绍Visual Leak Detector的使用方法与步骤,然后再和读者一起初步的研究Visual Leak Detector的源代码,去了解Visual Leak Detector的工作原理。
使用Visual Leak Detector(1.0)
下面让我们来介绍如何使用这个小巧的工具。
首先从网站上下载zip包,解压之后得到vld.h, vldapi.h, vld.lib, vldmt.lib, vldmtdll.lib, dbghelp.dll等文件。将.h文件拷贝到Visual C++的默认include目录下,将.lib文件拷贝到Visual C++的默认lib目录下,便安装完成了。因为版本问题,如果使用windows 2000或者以前的版本,需要将dbghelp.dll拷贝到你的程序的运行目录下,或其他可以引用到的目录。
接下来需要将其加入到自己的代码中。方法很简单,只要在包含入口函数的.cpp文件中包含vld.h就可以。如果这个cpp文件包含了stdafx.h,则将包含vld.h的语句放在stdafx.h的包含语句之后,否则放在最前面。如下是一个示例程序:
#include <vld.h>
void main()
{

}
接下来让我们来演示如何使用Visual Leak Detector检测内存泄漏。下面是一个简单的程序,用new分配了一个int大小的堆内存,并没有释放。其申请的内存地址用printf输出到屏幕上。
#include <vld.h>
#include <stdlib.h>
#include <stdio.h>

void f()
{
int *p = new int(0x12345678);
printf("p=%08x, ", p);
}

void main()
{
f();
}
编译运行后,在标准输出窗口得到:
p=003a89c0

在Visual C++的Output窗口得到:

WARNING: Visual Leak Detector detected memory leaks!
---------- Block 57 at 0x003A89C0: 4 bytes ---------- --57号块0x003A89C0地址泄漏了4个字节
Call Stack: --下面是调用堆栈
d:\test\testvldconsole\testvldconsole\main.cpp (7): f --表示在main.cpp第7行的f()函数
d:\test\testvldconsole\testvldconsole\main.cpp (14): main –双击以引导至对应代码处
f:\rtm\vctools\crt_bld\self_x86\crt\src\crtexe.c (586): __tmainCRTStartup
f:\rtm\vctools\crt_bld\self_x86\crt\src\crtexe.c (403): mainCRTStartup
0x7C816D4F (File and line number not available): RegisterWaitForInputIdle
Data: --这是泄漏内存的内容,0x12345678
78 56 34 12 xV4..... ........

Visual Leak Detector detected 1 memory leak.
第二行表示57号块有4字节的内存泄漏,地址为0x003A89C0,根据程序控制台的输出,可以知道,该地址为指针p。程序的第7行,f()函数里,在该地址处分配了4字节的堆内存空间,并赋值为0x12345678,这样在报告中,我们看到了这4字节同样的内容。
可以看出,对于每一个内存泄漏,这个报告列出了它的泄漏点、长度、分配该内存时的调用堆栈、和泄露内存的内容(分别以16进制和文本格式列出)。双击该堆栈报告的某一行,会自动在代码编辑器中跳到其所指文件的对应行。这些信息对于我们查找内存泄露将有很大的帮助。
这是一个很方便易用的工具,安装后每次使用时,仅仅需要将它头文件包含进来重新build就可以。而且,该工具仅在build Debug版的时候会连接到你的程序中,如果build Release版,该工具不会对你的程序产生任何性能等方面影响。所以尽可以将其头文件一直包含在你的源代码中。
NIKE霸天虎 2010-01-27
  • 打赏
  • 举报
回复
最简单看任务管理器,或用内存泄露工具监测,这类工具GOOGLE就有
精锐掷矛手 2010-01-27
  • 打赏
  • 举报
回复
收藏
wwgddx 2010-01-27
  • 打赏
  • 举报
回复
查找new,看有没有对应的delete
LiuYinChina 2010-01-27
  • 打赏
  • 举报
回复
_CrtSetBreakAlloc(分配号)。(查找特定的内存泄露十分有用)
加载更多回复(2)

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧