下载Valgrind工具源码:
http://www.valgrind.org/downloads/valgrind-3.14.0.tar.bz2
解压缩:
tar -jxvf valgrind-3.14.0.tar.bz2
进入安装后的目录进行安装:
cd valgrind-3.14.0
./configure --prefix=/home/NJR/valgrind
make
make install
配置环境变量:
vi /etc/profile
最后一行加入:export PATH=$PATH:/home/NJR/valgrind/bin
生效环境变量:source /etc/profile
假设想要检测的执行文件是main,并且想把检测结果输入到文件valgrind_report.log中,就执行下面语句:
valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --run-libc-freeres=yes --log-file=./valgrind_report.log ./test
如果只想把结果打印到屏幕上,就执行下面语句
valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --run-libc-freeres=yes ./test
举例子:
#include <iostream> void func(void) { int *x = (int *)malloc(8 * sizeof(int)); x[9] = 0; //数组下标越界 } //内存未释放 int main(void) { func(); return 0; }
执行编译命令:
gcc -Wall test.cpp -g -fno-inline -o test
运行后的结果,可以看到
==56206== Memcheck, a memory error detector ==56206== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==56206== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info ==56206== Command: ./test ==56206== Parent PID: 40069 ==56206== ==56206== Invalid write of size 4 ==56206== at 0x400514: getMemory() (test.cpp:6) ==56206== by 0x400525: main (test.cpp:12) ==56206== Address 0x5201064 is 4 bytes after a block of size 32 alloc'd ==56206== at 0x4C2DE4D: malloc (vg_replace_malloc.c:299) ==56206== by 0x400507: getMemory() (test.cpp:5) ==56206== by 0x400525: main (test.cpp:12) ==56206== ==56206== ==56206== HEAP SUMMARY: ==56206== in use at exit: 32 bytes in 1 blocks ==56206== total heap usage: 1 allocs, 0 frees, 32 bytes allocated ==56206== ==56206== 32 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==56206== at 0x4C2DE4D: malloc (vg_replace_malloc.c:299) ==56206== by 0x400507: getMemory() (test.cpp:5) ==56206== by 0x400525: main (test.cpp:12) ==56206== ==56206== LEAK SUMMARY: ==56206== definitely lost: 32 bytes in 1 blocks ==56206== indirectly lost: 0 bytes in 0 blocks ==56206== possibly lost: 0 bytes in 0 blocks ==56206== still reachable: 0 bytes in 0 blocks ==56206== suppressed: 0 bytes in 0 blocks ==56206== ==56206== For counts of detected and suppressed errors, rerun with: -v ==56206== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
原理:
1.定义一个全局的内存信息表,用来存储内存申请的文件名及位置
2.重载operator new/new[],保存内存申请信息
3.重载operator delete/delete[],删除内存申请信息
4.定义一个全局/静态常量,在程序结束时,核查内存信息表是否还存在内存申请信息,如果存在则说明发生内存泄漏,否则无内存泄漏
struct Info { void *ptr; const char *file_name; long line; }; Info ptr_list[1024]; unsigned int ptr_num = 0; int find_ptr(void *p) { for (unsigned int i = 0; i < ptr_num; ++i) { if (ptr_list[i].ptr == p) { return i; } } return -1; } void del_ptr(unsigned int i) { while(i+1 < ptr_num) { ptr_list[i] = ptr_list[i+1]; i++; } ptr_num--; } struct ProcEnd { ~ProcEnd() { for (unsigned int i = 0; i < ptr_num; ++i) { printf("file: %s, line: %d, memory leak!!!\n", ptr_list[i].file_name, ptr_list[i].line); } } }; void* operator new(size_t size, const char *file_name, long line) { printf("global new\n"); void *p = malloc(size); ptr_list[ptr_num].ptr = p; ptr_list[ptr_num].file_name = file_name; ptr_list[ptr_num].line = line; ptr_num++; return p; } void* operator new[](size_t size, const char *file_name, long line) { return operator new(size, file_name, line); } void operator delete(void *p) { int i = find_ptr(p); if (i != -1) { free(p); del_ptr(i); } else { printf("delete unknown pointer!!!\n"); } } void operator delete[](void *p) { operator delete(p); } ProcEnd end; struct BTNode { BTNode(char val) : val(val), left(nullptr), right(nullptr) {} char val; BTNode *left; BTNode *right; };
检验输出结果:
#include <iostream> int main() { int *i = new int(0); return 0; }
控制台打印信息:
global new
file: ../src/TEST.cpp, line: 197, memory leak!!!
可以看出发生了内存泄漏,并提示对应的文件名称和行号。