valgrind 是一套linux下的开源仿真调试工具集,遵循GPLv2许可协议,可以用于内存调试,内存泄漏检测以及性能分析。
valgrind包含下列一些工具:
Memcheck:内存错误检测器,这是最常用的工具,用于检测程序中的内存问题,如泄露、越界、非法指针等。memcheck会检测所有对内存的去写操作,一切对malloc()/free()/new/delete的调用都会被捕获,所以能检测以下问题:
对未初始化内存的使用;
读/写释放后的内存块;
读/写超出 malloc 分配的内存块;
读/写不适当的栈中内存块;
内存泄漏,指向一块内存的指针永远丢失;
不正确的 malloc/free 或 new/delete 匹配;
memcpy() 相关函数中的 dst 和 src 指针重叠。
Helgrind:它主要用来检查多线程程序中出现的竞争问题。Helgrind寻找内存中被多个线程访问,而又没有一贯加锁的区域,这些区域往往是线程之间失去同步的地方,而且会导致难以发觉的错误。Helgrind实现了名为Eraser的竞争检测算法,并做了进一步改进,减少了报告错误的次数。不过,Helgrind仍然处于实验状态。
Massif:堆栈分析器,它能测量程序在堆栈中使用了多少内存,告诉我们堆块,堆管理块和栈的大小。Massif能帮助我们减少内存的使用,在带有虚拟内存的现代系统中,它还能够加速我们程序的运行,减少程序停留在交换区中的几率。
Massif对内存的分配和释放做profile。程序开发者通过它可以深入了解程序的内存使用行为,从而对内存使用进行优化。这个功能对C++尤其有用,因为C++有很多隐藏的内存分配和释放。
linux安装口令
Debian 和 Ubuntu 可使用 apt 安装
sudo apt install valgrind
新建一个c文件memoryleak.c,使用malloc申请一块内存空间,但是不释放,如下:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *arr = malloc(sizeof(int) * 100);
return 0;
}
gcc -g -o memoryleak memoryleak.c
valgrind 默认是运行memcheck
valgrind ./memoryleak
==320== Memcheck, a memory error detector
==320== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==320== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==320== Command: ./memoryleak
==320==
==320==
==320== HEAP SUMMARY:
==320== in use at exit: 400 bytes in 1 blocks
==320== total heap usage: 1 allocs, 0 frees, 400 bytes allocated
==320==
==320== LEAK SUMMARY:
==320== definitely lost: 400 bytes in 1 blocks
==320== indirectly lost: 0 bytes in 0 blocks
==320== possibly lost: 0 bytes in 0 blocks
==320== still reachable: 0 bytes in 0 blocks
==320== suppressed: 0 bytes in 0 blocks
==320== Rerun with --leak-check=full to see details of leaked memory
==320==
==320== For lists of detected and suppressed errors, rerun with: -s
==320== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
可以看到第9行显示,申请了1个 400 字节的内存空间,但是没有释放。
添加--leak-check=full
参数,可以看到内存泄漏的更多细节。
==426== Memcheck, a memory error detector
==426== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==426== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==426== Command: ./memoryleak
==426==
==426==
==426== HEAP SUMMARY:
==426== in use at exit: 400 bytes in 1 blocks
==426== total heap usage: 1 allocs, 0 frees, 400 bytes allocated
==426==
==426== 400 bytes in 1 blocks are definitely lost in loss record 1 of 1
==426== at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==426== by 0x10914A: main (memoryleak.c:6)
==426==
==426== LEAK SUMMARY:
==426== definitely lost: 400 bytes in 1 blocks
==426== indirectly lost: 0 bytes in 0 blocks
==426== possibly lost: 0 bytes in 0 blocks
==426== still reachable: 0 bytes in 0 blocks
==426== suppressed: 0 bytes in 0 blocks
==426==
==426== For lists of detected and suppressed errors, rerun with: -s
==426== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
可以看到第13行显示,内存泄漏发生在 memoryleak.c 的第6行代码。
接着,我们增加一行代码修复内存泄漏
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *arr = malloc(sizeof(int) * 100);
free(arr);
return 0;
}
gcc -g -o memoryleak memoryleak.c
valgrind ./memoryleak
==484== Memcheck, a memory error detector
==484== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==484== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==484== Command: ./memoryleak
==484==
==484==
==484== HEAP SUMMARY:
==484== in use at exit: 0 bytes in 0 blocks
==484== total heap usage: 1 allocs, 1 frees, 400 bytes allocated
==484==
==484== All heap blocks were freed -- no leaks are possible
==484==
==484== For lists of detected and suppressed errors, rerun with: -s
==484== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
可以看到内存泄漏已经消除。