C/C++的程序员完成程序开发后,除了实现功能以外,还会是否存在内存泄漏的问题,特别是在复杂的应用程序中,肉眼review代码很难完全检查可能存在的出内存的泄漏问题,我们需要借助工具进行内存检测。
Valgrind是一个Linux下灵活的调试和剖析可执行工具。它由在软件层提供综合的CPU内核,和一系列调试、剖析的工具组成。架构是模块化的,所以可以在不破坏现有的结构的基础上很容易的创建出新的工具来。
Memcheck
本文主要介绍的就是使用该工具进行程序的内存泄漏问题的检测和定位。
Callgrind
Cachegrind
Helgrind
Massif
特点
不足
CentOS7中直接使用命令进行安装
yum install -y valgrind
编写不释放内存的示例代码
#include
int main()
{
int *p_num = new int(10);
int num = 100;
p_num = #
printf("num = %d\n", *p_num);
}
进行编译,注意,在编译过程中加入-g
能够定位内存泄漏的代码位置,帮助我们进行问题排查。
g++ -g -o test.so main.c
## 控制台查看
valgrind --tool=memcheck --leak-check=full ./test.so
## 生成检测结果到文件
valgrind --log-file=valgrind.log --tool=memcheck --leak-check=full --show-leak-kinds=all ./test.so
==73506== Memcheck, a memory error detector
==73506== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==73506== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==73506== Command: ./test.so
==73506==
num = 100
==73506==
==73506== HEAP SUMMARY:
==73506== in use at exit: 4 bytes in 1 blocks
==73506== total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==73506==
==73506== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==73506== at 0x4C2A593: operator new(unsigned long) (vg_replace_malloc.c:344)
==73506== by 0x40067E: main (main.c:5)
==73506==
==73506== LEAK SUMMARY:
==73506== definitely lost: 4 bytes in 1 blocks
==73506== indirectly lost: 0 bytes in 0 blocks
==73506== possibly lost: 0 bytes in 0 blocks
==73506== still reachable: 0 bytes in 0 blocks
==73506== suppressed: 0 bytes in 0 blocks
==73506==
==73506== For lists of detected and suppressed errors, rerun with: -s
==73506== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
主要关注的模块
HEAP SUMMARY
:输出堆上内存变化的统计信息
LEAK SUMMARY
:内存泄漏统计信息
实际分析
valgrind提示在程序退出前,还有4bytes空间未释放,分析日志中提示by 0x40067E: main (main.c:5)
中的代码int *p_num = new int;
没有释放,前面也提到了因为在编译中加了-g
的参数,所以才能在运行介绍后,定位到没有释放内存模块申请内存的具体代码位置。
从代码看,最开始申请了指向一个值为10的int数,然后将指针重新指向了其他地址,于是原来开辟的那块内存就无法进行释放操作了。
按提示释放内存
修改后的代码如下:
#include
int main()
{
int *p_num = new int(100);
printf("num = %d\n", *p_num);
if (p_num != NULL)
{
delete p_num;
p_num = NULL;
}
}
继续测试,结果如下:
$ g++ -g -o test.so main.c
$ valgrind --tool=memcheck --leak-check=full ./test.so
==77914== Memcheck, a memory error detector
==77914== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==77914== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==77914== Command: ./test.so
==77914==
num = 100
==77914==
==77914== HEAP SUMMARY:
==77914== in use at exit: 0 bytes in 0 blocks
==77914== total heap usage: 1 allocs, 1 frees, 4 bytes allocated
==77914==
==77914== All heap blocks were freed -- no leaks are possible
==77914==
==77914== For lists of detected and suppressed errors, rerun with: -s
==77914== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
错误提示与原因对应关系如下:
uninitialisedvalue
:使用了未初始化的变量Invalid read/write
:内存读写越界/读写已经释放的内存Source anddestination overlap
:内存覆盖