C/C++相比其他高级编程语言,具有指针的概念,指针即是内存地址。C/C++可以通过指针来直接访问内存空间,效率上的提升是不言而喻的,是其他高级编程语言不可比拟的;比如访问内存一段数据,通过指针可以直接从内存空间读取数据,避免了中间过程函数压栈、数据拷贝甚至消息传输等待。指针是C/C++的优势,但也是一个隐患,指针是一把双刃剑,由于内存交给了程序员管理,这是存在隐患的;人嘛总会有疏忽的时候,如果申请了内存,一个疏忽忘记释放了,未释放的内存将不能被系统再申请使用,即是一直占用又不能使用,俗称内存泄露;久而久之,系统长时间运行后将申请不到内存,系统上所有任务执行失败,只能重启系统。内存交给了程序员管理,除了内存泄露的情况外,还可能引起其他的问题,总结起来包括如下几点。
虽然动态内存(这里默认指的是堆上的动态内存,由程序员管理;栈上的动态内存由系统管理)存在一定的隐患,可靠性取决于程序员的认真和细心,但因为其具有优良的灵活性和高效率以及内存复用,在实际应用中,对于一些动态数据交互场合,动态内存往往是首选。因此,一方面除了程序员本身的谨慎使用,另一方面也涌现出各类“内存异常“的检测工具,毕竟当代码量数以万计时,依靠人力去检查是不切实际的。
虽然动态内存存在隐患,但有时候又不得不使用,内存泄露也就成为一个必须杜绝的敏感问题;有需求就会有相应的解决方法,目前已存在许多优秀的内存泄露检测工具,除了我们常用的Valgrind外,还有mtrace、dmalloc、memwatch等优秀工具。
工具 | 描述 |
---|---|
valgrind | 一个强大开源的程序检测工具集合 |
mtrace | GNU扩展, 用来跟踪malloc, mtrace为内存分配函数(malloc, realloc, memalign, free)安装hook函数 |
dmalloc | 用于检查C/C++内存泄露(leak)的工具,即检查是否存在直到程序运行结束还没有释放的内存,以一个运行库的方式发布 |
memwatch | 和dmalloc一样,它能检测未释放的内存、同一段内存被释放多次、位址存取错误及不当使用未分配之内存区域 |
mpatrol | 一个跨平台的 C++ 内存泄漏检测器 |
dbgmem | |
Electric Fence |
Valgrind是一款基于linux平台开源的内存检测工具集合,功能强大,使用广泛。利用Valgrind工具,在检测出文章开头提及的动态内存隐患,即是Valgrind工具中的内存检测组件Memcheck, Memcheck支持的功能包括:
Valgrind功能强大,是一个工具集合,除了Memcheck工具外,还提供Cachegrind、Helgrind、Callgrind、Massif工具。
与gprof类似的分析工具,但它对程序的运行观察更是入微,能给我们提供更多的信息。和gprof不同,它不需要在编译源代码时附加特殊选项,但加上调试选项是推荐的。Callgrind收集程序运行时的一些数据,建立函数调用关系图,还可以有选择地进行cache模拟。在运行结束时,它会把分析数据写入一个文件。callgrind_annotate可以把这个文件的内容转化成可读的形式。
Cache分析器,它模拟CPU中的一级缓存I1,Dl和二级缓存,能够精确地指出程序中cache的丢失和命中。如果需要,它还能够为我们提供cache丢失次数,内存引用次数,以及每行代码,每个函数,每个模块,整个程序产生的指令数。这对优化程序有很大的帮助。
它主要用来检查多线程程序中出现的竞争问题。Helgrind寻找内存中被多个线程访问,而又没有一贯加锁的区域,这些区域往往是线程之间失去同步的地方,而且会导致难以发掘的错误。Helgrind实现了名为“Eraser”的竞争检测算法,并做了进一步改进,减少了报告错误的次数。不过,Helgrind仍然处于实验阶段。
堆栈分析器,它能测量程序在堆栈中使用了多少内存,告诉我们堆块,堆管理块和栈的大小。Massif能帮助我们减少内存的使用,在带有虚拟内存的现代系统中,它还能够加速我们程序的运行,减少程序停留在交换区中的几率。
可以根据core提供的功能,编写自定义的内存调试工具 。
以上工具集介绍引自Linux下几款C++程序中的内存泄露检查工具文章,更新详细的介绍可以阅读原文,总结得非常好。
Valgrind内存检测的原理是,Valgrind实现一个程序运行的虚拟环境,待检测的应用程序在Valgrind的虚拟环境中运行,Valgrind能够实时监测程序中内存申请、使用、释放的情况,并记录一些正常运行的有效信息和可能存在内存异常的信息,输出到终端或者用户指定的文件中。
Valgrind工具实用且使用广泛,大多数主流linux系统发行版都已集成Valgrind工具,在终端输入“valgrind”
,如系统没有安装Valgrind工具会提示以下安装信息。
acuity@ubuntu:~$ valgrind
The program 'valgrind' is currently not installed. You can install it by typing:
sudo apt install valgrind
Valgrind安装可以下载源码后安装,也通过系统源在线安装,Ubuntu推荐在线安装。
sudo apt install valgrind
安装完成,输入“valgrind”
命令,提示以下信息,表示安装成功。
acuity@ubuntu:~$ valgrind
valgrind: no program specified
valgrind: Use --help for more information.
"-g"
,保留调试信息valgrind --tool=memcheck --leak-check=full ./file
,–leak-check=full
表示检测所有内存泄露valgrind -h
查看帮助信息例子uninit.c
:
#include
int main(int argc, char * argv [ ])
{
int *p = NULL;
printf("address [0x%p]\r\n", p);
*p = 0;
return 0;
}
访问空指针,特别是往空指针写数据时,基本会引起段错误(Segmentation fault ),此时系统会产生core dump 文件,通过 core dump文件结合GDB工具也很容易找出访问空指针的地方。
例子free.c
:
#include
#include
int main(int argc, char * argv [ ])
{
int *p = NULL;
p = malloc(4);
if (p == NULL)
{
perror("malloc failed");
}
printf("address [0x%p]\r\n", p);
free(p);
*p = 0;
return 0;
}
例子over.c
:
#include
#include
int main(int argc, char * argv [ ])
{
int *p = NULL;
p = malloc(4);
if (p == NULL)
{
perror("malloc failed");
}
printf("address [0x%p]\r\n", p);
p[4] = 0;
free(p);
return 0;
}
例子leak.c
:
#include
#include
int main(int argc, char * argv [ ])
{
int *p = NULL;
p = malloc(4);
if (p == NULL)
{
perror("malloc failed");
}
printf("address [0x%p]\r\n", p);
return 0;
}
例子refree.c
:
#include
#include
int main(int argc, char * argv [ ])
{
int *p = NULL;
p = malloc(4);
if (p == NULL)
{
perror("malloc failed");
}
printf("address [0x%p]\r\n", p);
free(p);
free(p);
return 0;
}
例子nolike.c
:
#include
#include
int main(int argc, char * argv [ ])
{
int *p = NULL;
p = (int*)malloc(sizeof(int));
if (p == NULL)
{
perror("malloc failed");
}
printf("address [0x%p]\r\n", p);
delete p;
return 0;
}
内存泄露检测包括动态内存使用的规范性,根本的解决办法是程序员保持良好的编码习惯,使用动态内存时谨慎考虑,保证申请与释放的必然性。因为,一些隐晦的问题可能需要在特定条件下才会引起内存泄露,依赖于检测工具也是需要长时间运行软件才能发现。
Valgrind—memcheck工具更多是用于检测内存泄露,空指针、野指针、内存越界、重复释放等问题,会引系统段错误(Valgrind),使用GDB结合系统产生的core dump文件,也能快速定位到调用位置。而内存泄露不会立即导致系统异常,只有运行一定时间后系统申请不到内存时才会引起异常。因此,借助Valgrind—memcheck工具来检测内存泄露是一个高效的方法之一。
【1】Linux下几款C++程序中的内存泄露检查工具
【2】Valgrind学习总结