Linux内存泄露检测全攻略:3大工具对比(mtrace、Valgrind、GNU扩展)

检测维修 0 130

在Linux这个环境之下,去编写C或者C++程序,存在着众多工具,然而最主要的编译器依旧是gcc以及g++。最近在进行STL里的List编程的时候,至于为了检测所编写的代码是不是会出现内存泄漏这种情况,从而去了解了一番相关的知识。

通过动态内存分配方式来运行的所有程序,均存在遇上内存泄露问题的可能性,于Linux环境之中,存在三种常用工具用以检测内存泄露的状况,这三种工具分别是:

查阅,http://elinux.org/Memory_Debuggers 。

偶然发现的内存泄露检测工具比较

工具描述

一个强大开源的程序检测工具

GNU的扩展,它是用于跟踪malloc的,mtrace这个东西呢,是为内存分配函数,也就是malloc、realloc、memalign、free这些函数,去安装hook函数哦。

dmalloc

针对C/C++开展内存泄露检查的工具,也就是去查验有没有那种一直到程序运行终止都未曾被释放的内存,它是以一种运行库的形式予以发布 。

memwatch

它跟dmalloc一样,能够检测出未被释放的内存,同一段内存被多次释放的情况,位址存取出现的错误,以及对未分配内存区域的不当使用 。

mpatrol

一个跨平台的 C++ 内存泄漏检测器

dbgmem

Electric Fence

1 被测程序

为了便于测试,我们撰写了一个简易程序,此番程序循环十次,每一次都申请了一个具备一百个字节的单元,且不予以释放 。

2 valgrind 2.1 valgrind介绍

是否可以这样讲,不存在一种内存检查工具,是能够在Linux环境下得以使用的呢,其实并非如此,比如说开源的valgrind工具,它实际上还是相当不错的 。

主页下载

valgrind

参照

Valgrind简单用法

Unix下C程序内存泄漏检测工具Valgrind安装与使用

valgrind 的使用简介

应用 Valgrind 发现 Linux 程序的内存问题

如何运用,Valgrind memcheck工具,从而于,C/C++范畴内,开展内存泄漏检测工作 。

2.2 安装

源码安装

获取最新版的valgrind进行下载,依据其中README所给出的提示,在完成安装操作之后,便能够运用这个工具去检测诸如内存泄露以及内存越界之类的情况,。

/configure
make
sudo make install

当然也可以使用发行版的自带的源中安装

sudo apt install valgrind

这是个不存在界面的内存检测工具,安装完毕后,输入valgrind ls -l去验证该工具是不是工作得正常些(这属于README里的方法,实际上是对ls -l命令进行内存检测的验证),要是你瞧见一堆信息那就表明你的工具可投入使用了。

2.3 使用说明

有一个名为Valgrind的工具包,它涵盖了好些工具,其中有Memcheck,还有Cachegrind ,另外还有Helgrind ,也有Callgrind ,甚至还有Massif 。

Memcheck

有一种工具,是被最为频繁常常用到的,它的用途是而去检测程序里所出现的内存方面的问题,程序之中所有针对于内存的读写操作全部都会被检测出来,所有一切对于malloc()/free()/new/delete的调用也照样都会被捕获到。所以呢,Memcheck这个工具主要是用于检查下面的程序所存在的错误 。

内容描述

使用未初始化的内存

Use of uninitialised memory

使用已经释放了的内存

试图在已被释放的内存上进行读取,或者 试图对其执行写操作 。 。

使用超过 malloc分配的内存空间

对堆栈的非法访问

申请的空间是否有释放

Memory leaks发生的情况是,指向通过malloc分配的内存块的指针永远丢失了,。

malloc去申请内存同free来释放内存二者之间的匹配,new去申请内存与delete来释放内存二者之间的匹配。

使用malloc/new/new时出现的不匹配情况,与free/delete/delete相对比 ,存在不匹配情况 。

src和dst的重叠

这些问题常常是C/C++程序员最为头疼的问题,Memcheck在这儿帮了大忙,起到了很大的作用 。

Callgrind

有一种和gprof类似的分析工具,它对程序运行的观察算得上是更加细致入微,能够给我们提供出更多的信息。它与gprof不一样,它并不需要在编译源代码之际附加特殊选项,不过加上调试选项是被推荐的。Callgrind会收集程序运行期间的一些数据,进而建立函数调用关系图,并且还能够有选择地去进行cache模拟。在运行完了的时候,它会将分析数据写入到一个文件当中。callgrind_annotate能够把这个文件的内容转化成可以读的形式。

Cachegrind

能够专门模拟CPU里一级缓存I1、Dl以及二级缓存的Cache分析器,可精准指出程序里cache的丢失与命中情况,若有需要,还可为我们给出cache丢失次数、内存引用次数,以及由每行代码、每个函数、每个模块乃至整个程序所产生的指令数,这对优化程序有着极大的帮助 。

Helgrind

它主要是被用于检查多线程程序里所出现的竞争方面的问题,Helgrind寻觅内存当中那些被众多线程访问,然而却未曾一直加锁的区域,这些区域常常是线程之间没能够达成同步的地方,并且还会引发难以被发掘出来的错误,Helgrind实现了被称作“Eraser”的竞争检测算法,并且做了额外的改进,从而减少了报告错误的次数,不过,Helgrind依旧处在实验阶段。

Massif

能够测量程序于堆栈里所使用内存数量的堆栈分析器,会告知我们关于堆块、堆管理块以及栈的大小。Massif可助力我们降低内存的使用,在具备虚拟内存的现代系统当中,它还能够加快我们程序的运行速度,减小程序停留在交换区里的概率。

除此之外,lackey以及nulgrind同样会予以提供,lackey属于小型工具,极少会被用到,nulgrind仅仅是用来为开发者呈现怎样去创建一款工具 。

注意

Valgrind不检查静态分配数组的使用情况

Valgrind占用了更多内存,这内存量可达两倍于你程序的正常使用量,是不同寻常的多,多到两倍那么多 。

倘若你运用Valgrind去查验使用大量内存的程序,便会遭遇问题,它极有可能会耗费漫长的时间去运行测试,。

2.4 使用说明

编译程序

g++ -g -o leak leak.c 

针对被检测程序,加入这样的编译选项,即 –g -fno-inline ,以此来保留调试信息,不然的话,后续的valgrind就没办法显示出错行号 。

valgrind被设计得不具有侵入性,它直接在可执行文件上开展工作,所以在进行检查前面,无需重新编译,无需连接以及修改你的程序。要对一个程序实施检查是很简便的,仅仅需要执行下面的命令便行了。

使用名为valgrind的工具,以tool_name为工具名称,运行名为program_name的程序 。

例如,对于“ls -l”命令展开内存检验这事,仅仅只需去执行如下这般的命令便达成了 。

使用valgrind工具,其工具为memcheck,执行ls -l命令 。

小提示

Linux C++内存泄漏检测工具_Valgrind内存泄漏检测教程_linux下内存泄露检测工具介绍

要是不清楚存在哪些参数,能够先键入valgrind –tool= ,接着迅猛地按两下tab ,会给出linux系统的只不过是提示 ,同样的 ,要是你录入了valgrind –tool=mem而后迅猛地按两下tab ,linux系统会为你自行补齐 。

2.5 使用valgrind检测Memcheck

下面我们就可以用valgrind对我们的程序检测leak

valgrind,使用工具memcheck,将泄漏检查设置为完全检查模式,展示可达内存设置为yes,追踪子进程设置为yes状态,运行这个 ./leak程序。

当中,–leak-check=full,其所指的内容是,针对内存泄漏展开完全检查,。

把显示内存泄漏的地点设定 ,是通过 –show-reachable=yes来达成的, 。

–trace-children=yes是跟入子进程。

在程序以正常方式退出之际,valgrind 会自然而然地输出有关内存泄漏的信息,其原理是:

3 mtrace检测内存泄露 3.1 mtrace简介

在一般的linux发行版当中,存在着一个自带的工具,它能够颇为便利地替你达成这些事情,而这个工具便是mtrace 。

mtrace其实是GNU扩展函数,用来跟踪malloc。

安装hook函数,这些hook函数用于记录内存的申请和释放的trace信息,是为内存分配函数(malloc, realloc, memalign, free)的mtrace。

于程序内,这些trace信息能用以发觉内存泄漏,以及释放并非申请所得的内存。

当对mtrace进行调用时,mtrace会去检查环境变量MALLOC_TRACE ,该环境变量应当涵盖记录trace信息的文件路径 ,要是文件能够被成功打开 ,那么它的大小会被截断为0 。

假设MALLOC_TRACE未被设置,或者所设置的文件不具备可用性,又或者它是不可写的,那么hook函数将不会被安装,mtrace也不会产生预期的效果。

详细说明可参考man page:man 3 mtrace

3.2 mtrace使用

mtrace能监测程序是否内存泄露

#include 

setenv("MALLOC_TRACE", "mtrace.out", 1);

mtrace()

进行这样的操作,即使用gcc,添加-g选项,再添加-c选项,对leak_mtrace.c文件进行处理,使其生成leak_mtrace.o文件,最后以这样的指令格式。std=gnu9x -Wall

./leak_mtrace 

mtrace a.out  mtrace.out

4 dmalloc

dmalloc是一种工具,用于检查C/C++内存泄露,也就是检查是否存在程序运行结束时仍未释放的内存,它还能够精确指出是在哪个源文件的第几行 。

5,Linux内核的Kmemleak ,5.1,Kmemleak检测工具介绍, 。

Kmemleak,是工作于内核态的、内核自带的内核泄露检测工具,并且,其源代码处在mm/kmemleak.c那里。

Kmemleak于内核态运行,它给出一种可选择的内核泄漏检测方式,该方式跟跟踪内存收集器类似,当单独的对象没被释放时, 在 /sys/kernel/debug/kmemleak里会有其报告记录, Kmemcheck可以协助定位大部分内存错误的上下文 。

5.2 Kmemleak使用过程概述

内存扫描参数能够被修改,其修改方式是通过朝着/sys/kernel/debug/kmemleak 文件实施写入操作。所涉及的参数有着如下这般的使用情形。

off 禁用kmemleak(不可逆)
stack=on 启用任务堆栈扫描(default)
stack=off 禁用任务堆栈扫描
scan=on 启动自动记忆扫描线程(default)
scan=off 停止自动记忆扫描线程
scan= 设置n秒内自动记忆扫描
scan 开启内核扫描
clear 清除内存泄露报告
dump= 转存信息对象在

通过“kmemleak = OFF”此举,还能够于启动之际,在内核命令行中将Kmemleak予以禁用。在对kmemleak展开初始化以前,内存的分配动作或者释放动作,这些均被存储于一个前期日志缓冲区之中。而这个缓冲区的大小,是借助配CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE来进行设置的。

5.3 Kmemleak动态检测原理

经过的kmalloc、vmalloc、kmem_cache_alloc等内存分配会追踪其指针,和其他的分配大小以及堆栈跟踪信息一起,存于PRIO搜索树。对应的释放函数调用跟踪以及指针就会从kmemleak数据结构里被移除。

被分配的内存块,被视作是独立的,要是不存在指针指向它起始的地址,或者块的内部的任何一处位置,能够发觉扫描内存(涵盖已保存的寄存器)。这表明,有可能性不存在办法,为内核经由所分配的地址传递块到一个释放函数,所以,该块被认定为是一个内存泄漏 。

扫描算法步骤:

标记的所有,那些被分配对象,呈现为白色,稍后呢,要把剩余的白色物体,当作是独立的来考虑 。

自扫描存储器与所说的数据片段以及栈起始处起,对存储于PRIO搜索树里地址的值展开检查,假使发现了乃是一个白色对象的指针,那么该对象就会被添加入灰名单中。

扫描仪所扫出的呈现灰色的对象与之符配的那个地址,存在着这样的情况,一些原本是白色的物体其能够转变成为灰色,并且在添加的时候是于结束之际添加到那个灰名单里,一直持续到黑色集合被终结掉 。

被视作独立儿的,是那剩余下来的白色物体,且相关情况被报告并写入了/sys/kernel/debug/kmemleak 。

一些位于内核内部数据结构里的、关于分配的内存块的指针,并且它们无法被检测成孤儿。为了避免出现这种状况,kmemleak还能够存储数量方面的值,该值指向处于从内核内部数据结构里的一个块的地址起算的地址范围内的地址,而这个地址范围是需要找到的,目的是让块不被视作泄漏 。

5.4 kmem相关函数

在kernel源代码里,有个目录是include /linux/kmemleak.h,从这个目录当中,能够查看函数原型的头 。

函数功能

kmemleak_init

初始化kmemleak

kmemleak_alloc

一个内存块分配的通知

kmemleak_alloc_percpu

通知的一个percpu的内存块分配

kmemleak_free

通知的内存块释放

kmemleak_free_part

通知释放部分内存块

kmemleak_free_percpu

一个percpu内存块释放的通知

kmemleak_not_leak

当不是泄露时,标记对象

kmemleak_ignore

当泄漏时不扫描或报告对象

kmemleak_scan_area

添加扫描区域内的内存块

kmemleak_no_scan

不扫描的内存块

kmemleak_erase

删除一个指针变量的旧值

kmemleak_alloc_recursive

为kmemleak_alloc,只检查递归

kmemleak_free_recursive

为kmemleak_free,只检查递归

相关推荐: