c/c++内存泄漏检测

21 篇文章 0 订阅
15 篇文章 0 订阅

这几天突然想起了解一下c/c++内存泄漏检测方面的东西,在网上的这方面的介绍也有很多,现在我在这个把我自己感觉有用的在这里总结一下

内存泄漏简介及后果

wikipedia中这样定义内存泄漏:在计算机科学中,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。

最难捉摸也最难检测到的错误之一是内存泄漏,即未能正确释放以前分配的内存的 bug。 只发生一次的小的内存泄漏可能不会被注意,但泄漏大量内存的程序或泄漏日益增多的程序可能会表现出各种征兆:从性能不良(并且逐渐降低)到内存完全用尽。 更糟的是,泄漏的程序可能会用掉太多内存,以致另一个程序失败,而使用户无从查找问题的真正根源。 此外,即使无害的内存泄漏也可能是其他问题的征兆。

内存泄漏会因为减少可用内存的数量从而降低计算机的性能。最终,在最糟糕的情况下,过多的可用内存被分配掉导致全部或部分设备停止正常工作,或者应用程序崩溃。内存泄漏可能不严重,甚至能够被常规的手段检测出来。在现代操作系统中,一个应用程序使用的常规内存在程序终止时被释放。这表示一个短暂运行的应用程序中的内存泄漏不会导致严重后果。

在Windows 下的检测:

1. 使用crtdbg.h

Windows平台下面Visual Studio 调试器和 C 运行时 (CRT) 库为我们提供了检测和识别内存泄漏的有效方法,原理大致如下:内存分配要通过CRT在运行时实现,只要在分配内存和释放内存时分别做好记录,程序结束时对比分配内存和释放内存的记录就可以确定是不是有内存泄漏。

#define _CRTDBG_MAP_ALLOC                //输出内存泄漏的行号等信息, 这个必须放在crtdbg.h之前
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <crtdbg.h>
void GetMemory(char *p, int num)
{
    p = (char*)malloc(sizeof(char)* num);
}
int main()
{
    char *str = NULL;
    GetMemory(str, 100);

    cout << "Memory leak test!" << endl;
    _CrtDumpMemoryLeaks();

    return 0;
}

输出结果:

Detected memory leaks!
Dumping objects ->
{152} normal block at 0x00FD4098, 4 bytes long.
Data: <    > CD CD CD CD
  e : \my projects\cpp\hellovs2013\hellovs2013\helloworld.cpp(20) : {151} normal block at 0x00FDA5A0, 100 bytes long.
  Data : <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
         Object dump complete.
         程序“[5472] HelloVs2013.exe”已退出,返回值为 0 (0x0)。


crtdbg.h有个不好的就是虽然也能检测到new 操作法造成的泄漏,但是不能定位泄漏的位置。

定位具体的内存泄漏地方

1_CrtMemState s1, s2, s3;

若要在给定点对内存状态拍快照,请向 _CrtMemCheckpoint 函数传递 _CrtMemState 结构。 该函数用当前内存状态的快照填充此结构:

1_CrtMemCheckpoint( &s1 );

通过向 _CrtMemDumpStatistics 函数传递 _CrtMemState 结构,可以在任意点转储该结构的内容:

1_CrtMemDumpStatistics( &s1 );

若要确定代码中某一部分是否发生了内存泄漏,可以在该部分之前和之后对内存状态拍快照,然后使用 _CrtMemDifference 比较这两个状态:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#include <iostream>
using namespace std;
_CrtMemState s1, s2, s3;
void GetMemory(char *p, int num)
{
    p = (char*)malloc(sizeof(char)* num);
}
int main(int argc, char** argv)
{
    _CrtMemCheckpoint(&s1);
    char *str = NULL;
    GetMemory(str, 100);
    _CrtMemCheckpoint(&s2);
    if (_CrtMemDifference(&s3, &s1, &s2))
        _CrtMemDumpStatistics(&s3);
    cout << "Memory leak test!" << endl;
    _CrtDumpMemoryLeaks();
    return 0;
}

调试时,程序输出如下结果:

image

这说明在s1和s2之间存在内存泄漏!!!如果GetMemory不是在s1和s2之间调用,那么就不会有信息输出。


Linux平台下的内存泄漏检测

在上面我们介绍了,vs中在代码中“包含crtdbg.h,将 malloc 和 free 函数映射到它们的调试版本,即 _malloc_dbg 和 _free_dbg,这两个函数将跟踪内存分配和释放。 此映射只在调试版本(在其中定义了_DEBUG)中发生。 发布版本使用普通的 malloc 和 free 函数。”即为malloc和free做了钩子,用于记录内存分配信息。

Linux下面也有原理相同的方法——mtrace,http://en.wikipedia.org/wiki/Mtrace。方法类似,我这就不具体描述,参加给出的链接。这节我主要介绍一个非常强大的工具valgrind。如下图所示:

image

如上图所示知道:

==6118== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1 
==6118==    at 0x4024F20: malloc (vg_replace_malloc.c:236) 
==6118==    by 0x8048724: GetMemory(char*, int) (in /home/netsky/workspace/a.out) 
==6118==    by 0x804874E: main (in /home/netsky/workspace/a.out)

是在main中调用了GetMemory导致的内存泄漏,GetMemory中是调用了malloc导致泄漏了100字节的内存。

Things to notice: 
• There is a lot of information in each error message; read it carefully. 
• The 6118 is the process ID; it’s usually unimportant. 
• The first line ("Heap Summary") tells you what kind of error it is. 
• Below the first line is a stack trace telling you where the problem occurred. Stack traces can get quite large, and be 
confusing, especially if you are using the C++ STL. Reading them from the bottom up can help.

• The code addresses (eg. 0x4024F20) are usually unimportant, but occasionally crucial for tracking down weirder 
bugs.

The stack trace tells you where the leaked memory was allocated. Memcheck cannot tell you why the memory leaked, 
unfortunately. (Ignore the "vg_replace_malloc.c", that’s an implementation detail.) 
There are several kinds of leaks; the two most important categories are: 
• "definitely lost": your program is leaking memory -- fix it! 
• "probably lost": your program is leaking memory, unless you’re doing funny things with pointers (such as moving 
them to point to the middle of a heap block)

Valgrind的使用请见手册http://valgrind.org/docs/manual/manual.html


2.使用VLD工具

下载vld:http://vld.codeplex.com/releases/view/82311

         http://www.codeproject.com/tools/visualleakdetector.asp

使用 解压之后得到vld.h, vldapi.h, vld.lib, vldmt.lib, vldmtdll.lib, dbghelp.dll等文件。将.h文件和.lib文件拷贝到你要检测的工程文件所在的目录里(只针对此工程),将dbghelp.dll拷贝到你的程序的运行目录下。

用法:在包含入口函数的.cpp文件中加入语句#include "vld.h" #pragma comment(lib, "vld.lib") 即可。
编译正确后,在debug方式下运行:查看VC的输出信息:
有内存泄露显示:"WARNING: Visual Leak Detector detected memory leaks!"
没有内存泄露,此输出的信息为:"No memory leaks detected."

//#define _CRTDBG_MAP_ALLOC
#include <stdio.h>
#include <string.h>
#include <iostream>
//#include <crtdbg.h>

#include "vld.h"
#pragma comment(lib, "vld.lib")

using std::cout;
using std::endl;
void GetMemory(char *p, int num)
{
    p = (char*)malloc(sizeof(char)* num);
    int* ip = new int;
}

int main()
{
    char *str = NULL;
    GetMemory(str, 100);
    cout << "Memory leak test!" << endl;
    //_CrtDumpMemoryLeaks();
    return 0;
}
输出:

Visual Leak Detector Version 1.0 installed (multithreaded DLL).
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 153 at 0x01165528: 4 bytes ----------
  Call Stack:
    0x0F39D626 (File and line number not available): free_dbg
    0x0F39DBCD (File and line number not available): msize_dbg
    0x0F39DB7A (File and line number not available): msize_dbg
    0x0F39E5A9 (File and line number not available): malloc
    0x0F38C26F (File and line number not available): operator new
    e:\my projects\cpp\hellovs2013\hellovs2013\helloworld.cpp (21): GetMemory
    e:\my projects\cpp\hellovs2013\hellovs2013\helloworld.cpp (30): main
    f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c (626): __tmainCRTStartup
    f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c (466): mainCRTStartup
    0x770B495D (File and line number not available): BaseThreadInitThunk
    0x778398EE (File and line number not available): RtlInitializeExceptionChain
    0x778398C4 (File and line number not available): RtlInitializeExceptionChain
  Data:
    CD CD CD CD                                                  ........ ........
---------- Block 152 at 0x0116FE88: 100 bytes ----------
  Call Stack:
    0x0F39D626 (File and line number not available): free_dbg
    0x0F39DBCD (File and line number not available): msize_dbg
    0x0F39DB7A (File and line number not available): msize_dbg
    0x0F39E5A9 (File and line number not available): malloc
    e:\my projects\cpp\hellovs2013\hellovs2013\helloworld.cpp (20): GetMemory
    e:\my projects\cpp\hellovs2013\hellovs2013\helloworld.cpp (30): main
    f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c (626): __tmainCRTStartup
    f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c (466): mainCRTStartup
    0x770B495D (File and line number not available): BaseThreadInitThunk
    0x778398EE (File and line number not available): RtlInitializeExceptionChain
    0x778398C4 (File and line number not available): RtlInitializeExceptionChain
  Data:
    CD CD CD CD    CD CD CD CD    CD CD CD CD    CD CD CD CD     ........ ........
    CD CD CD CD    CD CD CD CD    CD CD CD CD    CD CD CD CD     ........ ........
    CD CD CD CD    CD CD CD CD    CD CD CD CD    CD CD CD CD     ........ ........
    CD CD CD CD    CD CD CD CD    CD CD CD CD    CD CD CD CD     ........ ........
    CD CD CD CD    CD CD CD CD    CD CD CD CD    CD CD CD CD     ........ ........
    CD CD CD CD    CD CD CD CD    CD CD CD CD    CD CD CD CD     ........ ........
    CD CD CD CD                                                  ........ ........
Visual Leak Detector detected 2 memory leaks.
Visual Leak Detector is now exiting.




  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值