如何在linux下检测内存泄漏

本文深入探讨了Linux环境下C++程序内存泄漏的检测方法,包括new和delete的原理、内存检测子系统的实现、错误删除问题以及动态内存泄漏信息的检测。通过重载new和delete操作符,记录内存分配和释放信息,实现内存泄漏检测。文章还讨论了如何应对嵌套delete和错误的delete操作,以及如何动态监测内存泄漏,确保程序的稳定运行。
摘要由CSDN通过智能技术生成

本文实现了一个检测内存泄露的工具,包括了原理说明以及实现细节。

文章来自IBM社区(建议阅读原文),本文地址:https://www.ibm.com/developerworks/cn/linux/l-mleak/

【推荐阅读】

Linux文件系统详解

linux进程管理---实时调度

linux内核内存管理-缺页异常

linux内核内存管理-brk系统调用

简述

本文针对 linux 下的 C++ 程序的内存泄漏的检测方法及其实现进行探讨。其中包括 C++ 中的 new 和 delete 的基本原理,内存检测子系统的实现原理和具体方法,以及内存泄漏检测的高级话题。作为内存检测子系统实现的一部分,提供了一个具有更好的使用特性的互斥体(Mutex)类。

1.开发背景

在 windows 下使用 VC 编程时,我们通常需要 DEBUG 模式下运行程序,而后调试器将在退出程序时,打印出程序运行过程中在堆上分配而没有释放的内存信息,其中包括代码文件名、行号以及内存大小。该功能是 MFC Framework 提供的内置机制,封装在其类结构体系内部。

在 linux 或者 unix 下,我们的 C++ 程序缺乏相应的手段来检测内存信息,而只能使用 top 指令观察进程的动态内存总额。而且程序退出时,我们无法获知任何内存泄漏信息。为了更好的辅助在 linux 下程序开发,我们在我们的类库项目中设计并实现了一个内存检测子系统。下文将简述 C++ 中的 new 和 delete 的基本原理,并讲述了内存检测子系统的实现原理、实现中的技巧,并对内存泄漏检测的高级话题进行了讨论。

2.New和delete的原理

当我们在程序中写下 new 和 delete 时,我们实际上调用的是 C++ 语言内置的 new operator 和 delete operator。所谓语言内置就是说我们不能更改其含义,它的功能总是一致的。以 new operator 为例,它总是先分配足够的内存,而后再调用相应的类型的构造函数初始化该内存。而 delete operator 总是先调用该类型的析构函数,而后释放内存(图1)。我们能够施加影响力的事实上就是 new operator 和 delete operator 执行过程中分配和释放内存的方法。

new operator 为分配内存所调用的函数名字是 operator new,其通常的形式是 void * operator new(size_t size); 其返回值类型是 void*,因为这个函数返回一个未经处理(raw)的指针,未初始化的内存。参数 size 确定分配多少内存,你能增加额外的参数重载函数 operator new,但是第一个参数类型必须是 size_t。

delete operator 为释放内存所调用的函数名字是 operator delete,其通常的形式是 void operator delete(void *memoryToBeDeallocated);它释放传入的参数所指向的一片内存区。

这里有一个问题,就是当我们调用 new operator 分配内存时,有一个 size 参数表明需要分配多大的内存。但是当调用 delete operator 时,却没有类似的参数,那么 delete operator 如何能够知道需要释放该指针指向的内存块的大小呢?答案是:对于系统自有的数据类型,语言本身就能区分内存块的大小,而对于自定义数据类型(如我们自定义的类),则 operator new 和 operator delete 之间需要互相传递信息。

当我们使用 operator new 为一个自定义类型对象分配内存时,实际上我们得到的内存要比实际对象的内存大一些,这些内存除了要存储对象数据外,还需要记录这片内存的大小,此方法称为 cookie。这一点上的实现依据不同的编译器不同。(例如 MFC 选择在所分配内存的头部存储对象实际数据,而后面的部分存储边界标志和内存大小信息。g++ 则采用在所分配内存的头 4 个自己存储相关信息,而后面的内存存储对象实际数据。)当我们使用 delete operator 进行内存释放操作时,delete operator 就可以根据这些信息正确的释放指针所指向的内存块。

以上论述的是对于单个对象的内存分配/释放,当我们为数组分配/释放内存时,虽然我们仍然使用 new operator 和 delete operator,但是其内部行为却有不同:new operator 调用了operator new 的数组版的兄弟- operator new[],而后针对每一个数组成员调用构造函数。而 delete operator 先对每一个数组成员调用析构函数,而后调用 operator delete[] 来释放内存。需要注意的是,当我们创建或释放由自定义数据类型所构成的数组时,编译器为了能够标识出在 operator delete[] 中所需释放的内存块的大小,也使用了编译器相关的 cookie 技术。

综上所述,如果我们想检测内存泄漏,就必须对程序中的内存分配和释放情况进行记录和分析,也就是说我们需要重载 operator new/operator new[];operator delete/operator delete[] 四个全局函数,以截获我们所需检验的内存操作信息。

3.内存检测的基本实现原理

上文提到要想检测内存泄漏,就必须对程序中的内存分配和释放情况进行记录,所能够采取的办法就是重载所有形式的operator new 和 operator delete,截获 new operator 和 delete operator 执行过程中的内存操作信息。下面列出的就是重载形式:

void* operator new( size_t nSize, char* pszFileName, int nLineNum )
void* operator new[]( size_t nSize, char* pszFileName, int nLineNum )
void operator delete( void *ptr )
void operator delete[]( void *ptr )

我们为 operator new 定义了一个新的版本,除了必须的 size_t nSize 参数外,还增加了文件名和行号࿰

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值