valgrind
valgrind是运行在Linux上一套基于仿真技术的程序调试和分析工具,它包含一个内核,一个软件合成的CPU,和一系列的小工具,每个工具都可以完成一项任务──调试,分析,或测试等。
官方文档:https://www.valgrind.org/docs/manual/manual.html
valgrind 体系结构.png这里我们重点介绍:memcheck 是一个细粒度的的内存检查器。
安装
这里我们将valgrind安装在/usr/local/valgrind
目录下面。
mkdir tmp
wget http://www.valgrind.org/downloads/valgrind-3.14.0.tar.bz2
tar -jxvf valgrind-3.14.0.tar.bz2
./configure --prefix=/usr/local/valgrind
make
make install
- 配置环境变量
vim 编辑~/.bashrc文件
加入下面这段内容vim ~/.bashrc
使改变生效export PATH=$PATH:/usr/local/valgrind/bin/
source ~/.bashrc
常见内存错误
- 未初始化内存
- 内存读写越界
- 内存覆盖
- 动态内存管理错误
- 内存泄漏
使用命令格式
valgrind --tool=toolname args-val program args-pro
-
--tool
用于选择valgrind tool中的一种,后面接tool的名字。可以不加这个参考,则默认使用memcheck。 -
atgs-val
指valgrind可以添加的参数,用于配置单次运行时的特殊需求,可以通过valgrind -h
查看参数的各类的作用。 -
program
用于指定检测程序对象,valgrind对目标program的编译过程有些要求:- 打开调试模式
-g
,否则难以输出问题代码的具体行数。 - 关闭编译优化选项
- 打开调试模式
memcheck命令
- memcheck 命令
valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./a.out
- 结束 Memcheck 检查的做法一般是发送 SIGINT 信号,即
ctrl + c
。不要发送 SIGKILL 信号结束进程,否则无法生成检查报告。 - 使用valgrind会导致可执行文件的速度减慢 20 至 30 倍。
输出报告内容分析
memcheck 输出结果会报告5种内存泄露:
definitely lost 和 still reachable
definitely lost
表示确认丢失,程序中存在内存泄露,应尽快修复。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存则会报这个错误。
still reachable
void test01() { char *p = new char[1024]; }
void test02() { static char* p = new char[1024];}
int main()
{
test01();
test02();
}
image.png
indirectly lost
间接丢失。当使用了含有指针成员的类或结构时可能会报这个错误。这类错误无需直接修复,他们总是与definitely lost
一起出现,只要修复definitely lost
即可
class Object {
public:
Object() { _p = new char[1024]; }
~Object() { if(_p) delete _p; }
private:
char* _p = nullptr;
};
void test03() { Object* obj = new Object(); };
int main()
{
test03();
return 0;
}
image.png
possibly lost
可能丢失。大多数情况下应视为与definitely lost
一样需要尽快修复,除非你的程序让一个指针指向一块动态分配的内存(但不是这块内存起始地址)
-
示例一
image.pngvoid test04() { char* data = new char[1024]; static char* p = data + 1; } int main() { test04(); }
test04 测试结束后直到 main 函数返回前,静态指针 p 仍然可获得,但是 p 已经不再指向数组的起始地址。Memcheck 认为指向这块内存的指针可能已经丢失,会报告possibly lost
错误。 -
示例2
void test04() { char* data = new char[1024]; static char* p = data + 1; p = data; }
此时,静态指针 p 重新指向了数组的起始地址,所以 Memcheck 不会再报告
possibly lost
错误。但是 Memcheck 会报告still reachable
错误,这是因为静态指针指向的数组空间没有被释放,在测试进程结束前仍然可以获取到导致。 -
示例3
void test04() { char* data = new char[1024]; staticchar* p = data + 1; p = data; p = nullptr; }
在 test04 函数中再增加一行代码
p = nullptr
。
Memcheck 会输出definitely lost
错误。
因为 p 为空指针,不指向任何已分配的内存块,且没有指向数组的非起始地址,所以不会有still reachable
和possibly lost
这两种错误。
suppressed
已被解决。出现了内存泄露但系统自动处理了,可以无视这类错误。
参考资料
网友评论