在进行C++开发时,如果在windows平台上,使用MFC,则可以自动检测内存泄露,如果是win32或者console程序,不使用MFC,则需要自己进行处理。
下面是在总结的一些方法,均来自网上,也经历了实际检验,在此备份。
1. 利用 KDetectMemoryLeak.h来完成类似MFC重定义NEW宏的效果。可以完成泄露点的输出。
在代码的最后,采用_CrtDumpMemoryLeaks();
具体可以参见《VS2008内存泄露检测》文档,作者写的很清楚,在此谢谢。
KDetectMemoryLeak.h 源码:
#pragma once
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__,__LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
2. 对于无法定位到具体源代码的泄露,可以通过分析dump出来的信息来定位。
特别是在DLL库中,经常会出现这种情况。
比如:
{152} normal block at 0x01078320, 12 bytes long.
Data: 08 79 65 00 48 82 07 01 00 00 00 00
{151} normal block at 0x010782C0, 36 bytes long.
Data: CD CD CD CD CD CD CD CD 00 00 00 00 00 00 0000
{150} normal block at 0x01078248, 56 bytes long.
Data: F4 77 65 00 00 00 00 00 68 71 07 01 90 3A 0910
《软件调试》的702页介绍了堆块转储的细节,取其中的一个堆块为例:
{137} normal block at 0x01073790, 8 bytes long.
Data: <H7> 48 37 07 01 CD CD CD CD
137是堆块的分配序号,堆块的类型为普通堆块,位置为0x01073790,用户区长度为8字节。
Data后为用户数据区的前16字节,因为这个数据区只有8字节,所以即所有8字节。<H7>是这8字节的ASCII码显示(其它6字节为不可显示的ASCII码)。其中的CD CD CDCD 是CRT在分配堆块时自动填充的固定内容(《软件调试》P696)。这说明这8个字节的堆块,应用程序使用过前4个字节,后四个字节没有使用过。
对于这样的内存泄漏,有很多种办法,你首先可以试一下23.13.1节介绍的内存分配序号断点,也就是重新运行程序,在尽可能早的时候(比如入口),设置序号断点(将_crtBreakAlloc变量设置为要中断的序号,比如137),让CRT分配到指定的内存块时中断。中断下来后,可以根据栈回溯判断是哪个模块在分配内存,记录后,再退出程序,如果这个堆块仍出现在转储列表中,那么刚才那个模块便值得怀疑了。
如果你有被怀疑的模块源代码,那么可以使用23.15.3节介绍的方法让堆块转储信息中包含源程序的文件名和行号,即下面的样子:
C:\dig\dbg\author\code\chap23\MemLeak\MemLeak.cpp(22): {74} normal block at 0x00371000, 20 bytes long.
Data: CD CD CD CD CD CD CD CD CD CD CD CD CD CD CDCD
3.可以利用 vld 进行检测。
4.还可以利用 boundcheck,purify等工具进行检测。
刚将git lab从3.0升级到4.0,很多项目导入进来。打开项目的files页面,出现500 错误。
进入服务器,观察日志:/home/gitlab/gitlab/log/production.log 文件中找到错误:
Started GET "/cloudengine/package/tree/master" for 127.0.0.1 at 2013-01-07 10:41:04 +0800
Processing by TreeController#show as HTML
Parameters: {"project_id"=>"cloudengine/package", "id"=>"master"}
Rendered shared/_ref_switcher.html.haml (2.7ms)
Rendered shared/_clone_panel.html.haml (0.9ms)
Rendered tree/_head.html.haml (5.5ms)
Rendered tree/_tree_item.html.haml (4.1ms)
Rendered tree/_tree.html.haml (6.9ms)
Rendered tree/show.html.haml within layouts/project_resource (13.2ms)
Completed 500 Internal Server Error in 54ms
ActionView::Template::Error (Permission denied - (/home/gitlab/gitlab/tmp/cache/assets/sprockets%2F31f4736e6c39e984d230e798c530da2020130107-1340-1xps2q7, /home/gitlab/gitlab/tm\
p/cache/assets/CB6/C90/sprockets%2F31f4736e6c39e984d230e798c530da20)):
1: %tr{ class: "tree-item #{tree_hex_class(tree_item)}" }
2: %td.tree-item-file-name
3: = tree_icon(type)
4: %strong= link_to truncate(tree_item.name, length: 40), project_tree_path(@project, tree_join(@id || @commit.id, tree_item.name))
5: %td.tree_time_ago.cgray
6: %span.log_loading.hide
app/helpers/tree_helper.rb:33:in `tree_icon'
app/views/tree/_tree_item.html.haml:3:in `_app_views_tree__tree_item_html_haml___1248346142396777318_33157860'
app/helpers/tree_helper.rb:21:in `block in render_tree'
app/helpers/tree_helper.rb:15:in `each'
app/helpers/tree_helper.rb:15:in `render_tree'
app/views/tree/_tree.html.haml:34:in `_app_views_tree__tree_html_haml___1664153310566467946_59134580'
app/views/tree/show.html.haml:3:in `_app_views_tree_show_html_haml__592423701844535987_55745220'
app/controllers/tree_controller.rb:17:in `show'
chmod -R 777 ./tmp
重新启动,一切OK.
Description
Input
Output
Sample Input
dog ogday cat atcay pig igpay froot ootfray loops oopslay atcay ittenkay oopslay
Sample Output
cat eh loops
Hint
Source
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
struct Tire
{
struct Tire* next[26];
int tag;
};
char s1[100010][15],s2[15];
int main()
{
struct Tire *newnode();
void build(char s[15],int k,struct Tire *p);
int find(char s[15],struct Tire *p);
struct Tire *head;
int i,j,n,m,s,t,k;
t=1;
head=newnode();
while(1)
{
gets(s2);
if(strlen(s2)==0)
{
break;
}
for(i=0,j=0;i<=strlen(s2)-1;i++)
{
if(s2[i]!=' ')
{
s1[t][j++]=s2[i];
}else
{
break;
}
}
s1[t][j]='\0';
for(i=i+1,j=0;i<=strlen(s2)-1;i++)
{
s2[j]=s2[i]; j++;
}
s2[j]='\0';
build(s2,t,head);
t++;
}
while(scanf("%s",s2)!=EOF)
{
k=find(s2,head);
if(k==0)
{
printf("eh\n");
}else
{
printf("%s\n",s1[k]);
}
}
return 0;
}
struct Tire* newnode()
{
struct Tire *p;
p=new(struct Tire);
for(int i=0;i<=25;i++)
{
p->next[i]=NULL;
}
p->tag=0;
return p;
}
void build(char s[15],int k,struct Tire *p)
{
int a;
for(int i=0;i<=strlen(s)-1;i++)
{
a=s[i]-'a';
if(p->next[a]==NULL)
{
p->next[a]=newnode();
}
p=p->next[a];
}
p->tag=k;
}
int find(char s[15],struct Tire *p)
{
int a;
for(int i=0;i<=strlen(s)-1;i++)
{
a=s[i]-'a';
if(p->next[a]!=NULL)
{
p=p->next[a];
}else
{
return 0;
}
}
return p->tag;
}