如何监测内存泄漏

原创 2005年05月28日 11:25:00
作者:ariesram
版权申明
本文可以被自由转载,但是必须遵循如下版权约定:
1、保留本约定,并保留在文章的开头部分。
2、不能任意修改文章内容,或者删节,增加。如果认为本文内容有不当之处需要修改,请
与作者联系。
3、不能摘抄本文的内容,必须全文发表或者引用。
4、必须保留作者署名、注明文章出处。(本文授权给www.linuxaid.com.cn)
5、如不遵守本规定,则无权转载本文。

作者
ariesram
电子邮件地址
ariesram@linuxaid.com.cn, 或 ariesram@may10.ca
本文及本人所有文章均收集在bambi.may10.ca/~ariesram/articles/中。
本文授权给www.linuxaid.com.cn。

正文:
我 曾经参与过一个比较大的项目,在这个项目里面,我们没有一个完全确定的设计文档,所以程序的实现常常变动。虽然我们有一个比较灵活的框架,但是从程序的角 度来讲,它使我们的程序非常的混乱。直到发布的日期临近,我们还没有一个稳定的可以用来做alpha测试的版本。所以我们必须尽快的删除掉无用的代码,让 这个版本足够的稳定。但是,在这个没有足够规范的软件公司,我们没有时间也没有足够的精力来做边界测试之类的工作。所以我们只能采用变通的办法。在软件中 最大的问题就是内存泄漏。因为往往出现这样的情况,我们在一段代码中分配了内存,但是却没有释放它。这造成了很大的问题。我们需要一个简单的解决方案,能 够简单的编译进这个项目,在运行的时候,它能够产生一个没有被释放的内存的列表,用这个列表,我们能够改正程序的错误。这就是我们称之为内存跟踪的方法。 首先,我们需要一种代码,能够被加入到源代码中去,而且这种代码能够被重用。代码重用是一种很重要的特性,能够节省大量的时间和金钱以及程序员的劳动。另 外,我们的这种代码必须简单,因为我们当时已经没有那么多的时间和精力去完全重看一遍所有的代码来重新编写以及改正错误从而使内存跟踪能够起作用。

好 在,我们总能够找到解决的办法。首先,我们检查了代码,发现所有的代码都是用new来分配内存,用delete来释放内存。那么,我们能够用一个全程替 换,来替换掉所有的new和delete操作符吗?不能。因为代码的规模太大了,那样做除了浪费时间没有别的任何好处。好在我们的源代码是用C++来写成 的,所以,这意味着没有必要替换掉所有的new和delete,而只用重载这两个操作符。对了,值用重载这两个操作符,我们就能在分配和释放内存之前做点 什么。这是一个绝对的好消息。我们也知道该如何去做。因为,MFC也是这么做的。我们需要做的是:跟踪所有的内存分配和交互引用以及内存释放。我们的源代 码使用Visual C++写成,当然这种解决方法也可以很轻松的使用在别的C++代码里面。要做的第一件事情是重载new和delete操作符,它们将会在所有的代码中被使 用到。我们在stdafx.h中,加入:
#ifdef _DEBUG
inline void * __cdecl operator new(unsigned int size,
const char *file, int line)
{
};

inline void __cdecl operator delete(void *p)
{
};
#endif
这 样,我们就重载了new和delete操作符。我们用$ifdef和#endif来包住这两个重载操作符,这样,这两个操作符就不会在发布版本中出现。看 一看这段代码,会发现,new操作符有三个参数,它们是,分配的内存大小,出现的文件名,和行号。这对于寻找内存泄漏是必需的和重要的。否则,就会需要很 多时间去寻找它们出现的确切地方。加入了这段代码,我们的调用new()的代码仍然是指向只接受一个参数的new操作符,而不是这个接受三个参数的操作 符。另外,我们也不想记录所有的new操作符的语句去包含__FILE__和__LINE__参数。我们需要做的是自动的让所有的接受一个参数的new操 作符调用接受三个参数的new操作符。这一点可以用一点点小的技巧去做,例如下面的这一段宏定义,
#ifdef _DEBUG
#define DEBUG_NEW new(__FILE__, __LINE__)
#else
#define DEBUG_NEW new
#endif
#define new DEBUG_NEW
现 在我们所有的接受一个参数的new操作符都成为了接受三个参数的new操作符号,__FILE__和__LINE__被预编译器自动的插入到其中了。然 后,就是作实际的跟踪了。我们需要加入一些例程到我们的重载的函数中去,让它们能够完成分配内存和释放内存的工作。这样来做, #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);
};
#endif
另外,还需要用相同的方法来重载new[]和delete[]操作符。这里就省略掉它们了。
最后,我们需要提供一套函数AddTrack()和RemoveTrack()。我用STL来维护存储内存分配记录的连接表。
这两个函数如下:
typedef struct {
DWORD address;
DWORD size;
char file[64];
DWORD line;
} ALLOC_INFO;

typedef list 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;
}
}
};
现在,在我们的程序退出之前,allocList存储了没有被释放的内存分配。为了看到它们是什么和在哪里被分配的,我们需要打印出allocList中的数据。我使用了Visual C++中的Output窗口来做这件事情。
void DumpUnfreed()
{
AllocList::iterator i;
DWORD totalSize = 0;
char buf[1024];

if(!allocList)
return;

for(i = allocList->begin(); i != allocList->end(); i++) {
sprintf(buf, "%-50s: LINE %d, ADDRESS %d %d unfreed ",
(*i)->file, (*i)->line, (*i)->address, (*i)->size);
OutputDebugString(buf);
totalSize += (*i)->size;
}
sprintf(buf, "----------------------------------------------------------- ");
OutputDebugString(buf);
sprintf(buf, "Total Unfreed: %d bytes ", totalSize);
OutputDebugString(buf);
};
现在我们就有了一个可以重用的代码,用来监测跟踪所有的内存泄漏了。这段代码可以用来加入到所有的项目中去。虽然它不会让你的程序看起来更好,但是起码它能够帮助你检查错误,让程序更加的稳定。

Android 性能优化之内存泄漏的检测与修复

转载请注明本文出自 clevergump 的博客:http://blog.csdn.net/clevergump/article/details/52013873, 谢谢!在 Android 开发中,...
  • cleverGump
  • cleverGump
  • 2016年07月24日 14:30
  • 4132

Android 内存泄露和性能检测

Android Studio的内存分析界面 一般分析内存泄露, 首先运行程序,打开日志控制台,有一个标签Memory ,我们可以在这个界面分析当前程序使用的内存情况, 一目了然, 我们再也不需要苦苦...
  • u012482178
  • u012482178
  • 2018年01月06日 13:29
  • 287

c/c++内存泄漏检测工具

http://blog.jobbole.com/108506/?utm_source=tuicool&utm_medium=referral 初识 Visual Leak D...
  • u011001084
  • u011001084
  • 2016年12月05日 11:00
  • 201

内存泄漏监测

一、 在 MFC 中检测内存泄漏         假如是用MFC的程序的话,很简单。默认的就有内存泄露检测的功能。     我们用VS2005生成了一个MFC的对话框的程序,发现他可以自动的检...
  • caowei880123
  • caowei880123
  • 2012年08月17日 11:31
  • 991

Android内存泄漏分析及调试

首先了解一下dalvik的Garbage Collection:     如上图所示,GC会选择一些它了解还存活的对象作为内存遍历的根节点(GC Roots),比方说thread stack中的...
  • gemmem
  • gemmem
  • 2013年10月25日 11:31
  • 38220

Windows平台下的内存泄漏检测

在C/C++中内存泄漏是一个不可避免的问题,很多新手甚至有许多老手也会犯这样的错误,下面说明一下在windows平台下如何检测内存泄漏。 在windows平台下内存泄漏检测的原理大致如下。 1. ...
  • lanuage
  • lanuage
  • 2016年07月26日 22:06
  • 1134

如何检查C++中的内存泄漏 vs自带

如何检查C++中的内存泄漏  内存泄漏是编程中常常见到的一个问题,我所遇过的原因有两个: 1.分配完内存后忘记回收 2.代码有问题,造成想回收却无法回收,例如: int* p=...
  • iamherego
  • iamherego
  • 2016年06月06日 10:07
  • 1173

使用Chrome Profiles排查Web App的JS内存泄露小结

JS内存泄漏排查方法——Chrome Profiles
  • jlhx123456
  • jlhx123456
  • 2015年11月08日 18:35
  • 2640

Java内存泄漏的几大原因及预防检测

 Java 中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对...
  • chenleixing
  • chenleixing
  • 2015年01月28日 12:58
  • 3452

使用 Android Studio 检测内存泄漏与解决内存泄漏问题

本文在腾讯技术推文上 修改 发布。     http://wetest.qq.com/lab/view/63.html?from=ads_test2_qqtips&sessionUserType=B...
  • qq_27650777
  • qq_27650777
  • 2016年07月21日 16:21
  • 8362
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:如何监测内存泄漏
举报原因:
原因补充:

(最多只允许输入30个字)