C++ 在对象的d-tor期间检测内存泄漏
我的应用程序是基于dll的实现,在卸载期间可能会泄漏内存。我在卸载/重新加载循环期间(当宿主进程未终止时)注意到了这一点。托管进程的虚拟内存正在增加 我已经通过了代码检查,试图找到泄漏的代码,但没有找到任何 我正在寻找其他技术来检测卸载期间的内存泄漏(对象被销毁) 编辑:我正在使用win32(XP)平台 您是否有使用此类工具/程序的经验?C++ 在对象的d-tor期间检测内存泄漏,c++,memory-leaks,memory-management,malloc,C++,Memory Leaks,Memory Management,Malloc,我的应用程序是基于dll的实现,在卸载期间可能会泄漏内存。我在卸载/重新加载循环期间(当宿主进程未终止时)注意到了这一点。托管进程的虚拟内存正在增加 我已经通过了代码检查,试图找到泄漏的代码,但没有找到任何 我正在寻找其他技术来检测卸载期间的内存泄漏(对象被销毁) 编辑:我正在使用win32(XP)平台 您是否有使用此类工具/程序的经验? 谢谢如果你能在一个平台上编译你的代码,你当然应该试试这个工具。读一读,看看怎么做 这里有一个简单的例子 资料来源: $ cat -n leaky.cpp
谢谢如果你能在一个平台上编译你的代码,你当然应该试试这个工具。读一读,看看怎么做 这里有一个简单的例子 资料来源:
$ cat -n leaky.cpp
1 struct leaky
2 {
3 leaky()
4 :bytes(new char[256])
5 {
6 }
7
8 char* bytes;
9 };
10
11 int main()
12 {
13 leaky sieve;
14 return sizeof sieve;
15 }
16
建造:
$ make leaky
g++ -Wall -Wextra -Wshadow -pedantic -Wno-long-long -Wfloat-equal -Wcast-qual -g -I/opt/local/include -Weffc++ -Wall -I /opt/local/include -L/opt/local/lib leaky.cpp -o leaky
检查:
$ valgrind --leak-check=full ./leaky
==85800== Memcheck, a memory error detector
==85800== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==85800== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==85800== Command: ./leaky
==85800==
==85800==
==85800== HEAP SUMMARY:
==85800== in use at exit: 2,367 bytes in 33 blocks
==85800== total heap usage: 33 allocs, 0 frees, 2,367 bytes allocated
==85800==
==85800== 256 bytes in 1 blocks are definitely lost in loss record 6 of 9
==85800== at 0xB823: malloc (vg_replace_malloc.c:266)
==85800== by 0x5768D: operator new(unsigned long) (in /usr/lib/libstdc++.6.0.9.dylib)
==85800== by 0x576DA: operator new[](unsigned long) (in /usr/lib/libstdc++.6.0.9.dylib)
==85800== by 0x100000EE7: leaky::leaky() (leaky.cpp:4)
==85800== by 0x100000EB3: main (leaky.cpp:13)
==85800==
==85800== LEAK SUMMARY:
==85800== definitely lost: 256 bytes in 1 blocks
==85800== indirectly lost: 0 bytes in 0 blocks
==85800== possibly lost: 0 bytes in 0 blocks
==85800== still reachable: 2,111 bytes in 32 blocks
==85800== suppressed: 0 bytes in 0 blocks
==85800== Reachable blocks (those to which a pointer was found) are not shown.
==85800== To see them, rerun with: --leak-check=full --show-reachable=yes
==85800==
==85800== For counts of detected and suppressed errors, rerun with: -v
==85800== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 1 from 1)
您没有指定要查找的平台。我是windows开发人员,因此只能推荐windows解决方案。如果这就是你正在使用的,那么有很多商业和免费的工具可用。我个人使用的很少:Purify、BoundsChecker、UMDH、LeakDiag、DebugDiag 其中,我通常更喜欢UMDH。它是免费的,是安装的一部分。我发现它实际上比大多数其他工具(包括专业工具)更可靠,资源密集度更低。它的使用非常简单,文档可以在DTW安装附带的.chm文件中找到。最后,我个人发现,与许多其他工具相比,UMDH具有非常高的信噪比 DebugDiag是另一个很好的选择。据我所知,它使用与UMDH几乎相同的API,但使用起来稍微麻烦一些,因为它是基于UI的,而不是命令提示符,所以完成事情通常需要更多的点击,但对于新手来说,我推荐它而不是UMDH 更新: 有趣的是,大多数人的偏好是在malloc/free中插入自定义挂钩,然后在new/delete操作符中添加更多自定义挂钩代码 我强烈建议您查看一下UMDH,了解它是如何工作的,即使您认为在这种特定情况下没有必要。所有内存分配的核心是windows函数HeapAlloc/HeapFree。微软预见到泄漏检测方法的需求,已经提供了我们可以在该根级别使用的钩子 与自定义分配器挂钩相比,使用UMDH还有其他优势:
- 您将获得每个分配的完整堆栈跟踪,而不仅仅是由_文件和_行提供的__
- 它已经有了完整的报告和统计数据的汇总,这是您必须在拦截malloc/free的基础上编写的。您可以获得每个跟踪的#个分配、每个跟踪分配的#个字节以及分配的内存缓冲区列表,以便您可以实际分析泄漏的数据类型
- 检测其他人代码中发生的malloc/free泄漏,特别是在您控制的DLL中
- 检测来自其他内存分配函数(如CoTaskMemAlloc或SysStringAlloc)的泄漏
- 检测未正确释放的COM对象的泄漏
- 当您调用第三方API返回您忘记释放的缓冲区时,检测代码中的逻辑错误
- 您可以在任何代码库中立即使用UMDH,而无需反复添加自定义代码
- 您接受的方法仅在调试环境中有效。UMDH可以同样有效地使用,而无需对生产系统进行任何代码更改
因此,如果您通过DTW安装(顺便说一句,DTW还有其他很棒的调试功能)完全免费,那么为什么人们更喜欢使用自己的泄漏检测代码呢?我很久以前经常做的是: 我编写了自己的
mymalloc
、myrealloc
和myfree
(并重载了new
和delete
,以便它们调用我的函数。)然后我编写了malloc
和realloc
宏,它们调用了mymalloc
和myrealloc
,传递它们\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
和\uuuuuuuuuuuuuuuuuuuuuuu。mymalloc
所做的是:它调用了标准库的malloc
函数,分配了一个稍大的块,并在该块中插入了\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu文件和
。它还将所有分配的块保存在一个链表中,以便以后能够遍历它们
在程序退出时,我将遍历尚未释放的块列表,并打印出导致内存泄漏的文件和行
现在,我假设会有现成的工具,你可以为你做这类事情。除了Mike的答案(覆盖Malloc),你还可以覆盖Visual Studio中的新操作符和删除操作符
免责声明:我在2004中发现了这个代码,并把它包含在C++项目中。我不知道原始来源
下面是一个代码示例(我将其作为头文件memleak.h提供)。这是非常旧的代码,因此可能会有编译错误!但是,它确实说明了如何覆盖new和delete。它还将未释放的内存转储到文件中。如果代码中包含define\u调试,则此代码将生效
致以最良好的祝愿
#include <iostream>
#include <list>
using namespace std;
//void DumpUnfreed();
//void AddTrack(DWORD addr, DWORD asize, const char *fname, DWORD lnum);
//void RemoveTrack(DWORD addr);
typedef struct
{
DWORD address;
DWORD size;
char file[64];
DWORD line;
} ALLOC_INFO;
typedef list<ALLOC_INFO*> AllocList;
AllocList *allocList;
void AddTrack(DWORD addr, DWORD asize, const char *fname, DWORD lnum)
{
ALLOC_INFO *info;
if(!allocList)
{
allocList = new(AllocList);
}
info = new(ALLOC_INFO);
info->address = addr;
strncpy(info->file, fname, 63);
info->line = lnum;
info->size = asize;
allocList->insert(allocList->begin(), info);
};
void RemoveTrack(DWORD addr)
{
AllocList::iterator i;
if(!allocList)
return;
for(i = allocList->begin(); i != allocList->end(); i++)
{
if((*i)->address == addr)
{
allocList->remove((*i));
break;
}
}
};
void DumpUnfreed()
{
AllocList::iterator i;
DWORD totalSize = 0;
char buf[1024];
sprintf(buf, "-----------------------------------------------------------\n");
OutputDebugString(buf);
OutputDebugString("DSP.DLL: Detecting unfreed memory...\n");
if(!allocList)
{
OutputDebugString("No memory allocations were tracked!\n");
return;
}
for(i = allocList->begin(); i != allocList->end(); i++)
{
sprintf(buf, "%-50s:\t\tLINE %d,\t\tADDRESS %d\t%d unfreed\n",
(*i)->file, (*i)->line, (*i)->address, (*i)->size);
OutputDebugString(buf);
totalSize += (*i)->size;
}
sprintf(buf, "-----------------------------------------------------------\n");
OutputDebugString(buf);
sprintf(buf, "DSP.DLL Total Unfreed: %d bytes\n", totalSize);
OutputDebugString(buf);
sprintf(buf, "-----------------------------------------------------------\n");
OutputDebugString(buf);
};
#ifdef _DEBUG
inline void * __cdecl operator new(unsigned int size,
const char *file, int line)
{
void *ptr = (void *)malloc(size);
AddTrack((DWORD)ptr, size, file, line);
return(ptr);
};
inline void __cdecl operator delete(void *p)
{
RemoveTrack((DWORD)p);
free(p);
};
inline void * __cdecl operator new[ ] (unsigned int size, const char *file, int line)
{
void *ptr = (void *)malloc(size);
AddTrack((DWORD)ptr, size, file, line);
return(ptr);
};
inline void __cdecl operator delete[ ] (void *p)
{
RemoveTrack((DWORD)p);
free(p);
};
#endif
#ifdef _DEBUG
#define DEBUG_NEW new(__FILE__, __LINE__)
#else
#define DEBUG_NEW new
#endif
#define new DEBUG_NEW
#包括
#包括
使用名称空间std;
//void DumpUnfreed();
//void AddTrack(DWORD addr、DWORD asize、const char*fname、DWORD lnum);
//无效移除支架(DWORD addr);
类型定义结构
{
德沃德地址;
德沃德尺寸;
字符文件[64];
德沃德线;
}分配信息;
typedef列表AllocList;
阿洛