免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5537 | 回复: 6
打印 上一主题 下一主题

[Web] 如何监测apache的内存(也可以说内存具体的使用情况) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-08-03 13:42 |只看该作者 |倒序浏览
本人自己安装了一个第三方插件,在大流量测试的情况下发现内存剧烈增长从原来的平均91m增加到600m.我怎样确定插件和apache如何吃掉内存?现在一点头绪都没有,希望高人指点!不胜感谢

论坛徽章:
0
2 [报告]
发表于 2005-08-03 14:28 |只看该作者

如何监测apache的内存(也可以说内存具体的使用情况)

如何监测内存泄漏


作者
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<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;
}
}
      };
现在,在我们的程序退出之前,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);
      };
现在我们就有了一个可以重用的代码,用来监测跟踪所有的内存泄漏了。这段代码可以用来加入到所有的项目中去。虽然它不会让你的程序看起来更好,但是起码它能够帮助你检查错误,让程序更加的稳定。

论坛徽章:
0
3 [报告]
发表于 2005-08-05 18:02 |只看该作者

如何监测apache的内存(也可以说内存具体的使用情况)

重载的new和delete能正确调用相应的构造函数和析构函数吗?
不解...

论坛徽章:
0
4 [报告]
发表于 2005-08-06 14:02 |只看该作者

如何监测apache的内存(也可以说内存具体的使用情况)

完全可以

说说具体的

论坛徽章:
0
5 [报告]
发表于 2005-08-09 13:04 |只看该作者

如何监测apache的内存(也可以说内存具体的使用情况)

说说你的具体情况

论坛徽章:
0
6 [报告]
发表于 2005-08-12 11:15 |只看该作者

如何监测apache的内存(也可以说内存具体的使用情况)

如果对类的构造函数进行了重载,这样作也可以吗?

并且很多new并不是只传一个size参数的,你这样作只是替换最终的new(size)?还是对程序中出现的所有的new都起作用?

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
7 [报告]
发表于 2010-12-27 16:21 |只看该作者
感觉没有说清楚如何检测apache内存泄漏的问题
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP