腾讯teg挂了之后昨天又被其他部门捞起来了,面了20分钟左右,前面基本畅通无阻,但是问到如何检测内存泄漏的时候懵比了…………卒
介绍一个比较实用的工具 Valgrind,英文海星的朋友可以点这个 链接。一个新手教程。
Valgrind它在实质上还是一个debug工具集合,而其中最受欢迎就是 memcheck,用于检测内存泄漏。
其所有检测内容包括(个人总结
- 内存泄漏
- 使用未初始化的内存
- 内存越界
- 读写已经释放的内存
- 重复释放
内存泄漏
valgrind默认使用 memcheck参数来检查内存泄漏。所以一般只要 valgrind 程序名
即可。
比如源程序
#include <cstring>
void func()
{
char* ch = new char[10];
ch[0]='1';
}
int main()
{
func();
return 0;
}
对其进行检查
╰─○ valgrind ./learn
==26826== Memcheck, a memory error detector
==26826== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==26826== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==26826== Command: ./learn
==26826==
==26826==
==26826== HEAP SUMMARY:
==26826== in use at exit: 10 bytes in 1 blocks
==26826== total heap usage: 2 allocs, 1 frees, 72,714 bytes allocated <-- 注意看这里
==26826==
==26826== LEAK SUMMARY:
==26826== definitely lost: 10 bytes in 1 blocks
==26826== indirectly lost: 0 bytes in 0 blocks
==26826== possibly lost: 0 bytes in 0 blocks
==26826== still reachable: 0 bytes in 0 blocks
==26826== suppressed: 0 bytes in 0 blocks
==26826== Rerun with --leak-check=full to see details of leaked memory <-- 加参数详细查看
==26826==
==26826== For counts of detected and suppressed errors, rerun with: -v
==26826== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
╰─○ valgrind --leak-check=full ./learn
==28039== Memcheck, a memory error detector
==28039== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==28039== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==28039== Command: ./learn
==28039==
==28039==
==28039== HEAP SUMMARY:
==28039== in use at exit: 10 bytes in 1 blocks
==28039== total heap usage: 2 allocs, 1 frees, 72,714 bytes allocated
==28039==
==28039== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1 <-- 注意看这里
==28039== at 0x4C2DC6F: operator new[](unsigned long) (vg_replace_malloc.c:423)
==28039== by 0x1087BB: func() (learn.cpp:17) <-- 定位
==28039== by 0x1087D2: main (learn.cpp:23)
==28039==
==28039== LEAK SUMMARY: <-- 泄漏总览
==28039== definitely lost: 10 bytes in 1 blocks
==28039== indirectly lost: 0 bytes in 0 blocks
==28039== possibly lost: 0 bytes in 0 blocks
==28039== still reachable: 0 bytes in 0 blocks
==28039== suppressed: 0 bytes in 0 blocks
==28039==
==28039== For counts of detected and suppressed errors, rerun with: -v
==28039== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
其他错误
一次一个错误太麻烦了,再写个错误比较多的程序。
#include <cstring>
#include <vector>
void func()
{
char *str1 = new char[10], *str2 = new char[20];
strcat(str2,"123");//str2未初始化
str1[12] = 'a'; //越界
delete[] str1;
str1[2] = 'b'; //读写释放内存
delete[] str1; //重复释放
}
int main()
{
func();
return 0;
}
检测如下
–track-origins=yes 参数会将未初始化的错误和其他错误定位
╰─○ valgrind --leak-check=full --track-origins=yes ./learn
==28876== Memcheck, a memory error detector
==28876== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==28876== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==28876== Command: ./learn
==28876==
==28876== Conditional jump or move depends on uninitialised value(s) <-- 未初始化
==28876== at 0x108824: func() (learn.cpp:18)
==28876== by 0x108884: main (learn.cpp:31)
==28876== Uninitialised value was created by a heap allocation
==28876== at 0x4C2DC6F: operator new[](unsigned long) (vg_replace_malloc.c:423)
==28876== by 0x108809: func() (learn.cpp:17) <-- 具体定位
==28876== by 0x108884: main (learn.cpp:31)
==28876==
==28876== Invalid write of size 1 <-- 无效写
==28876== at 0x108845: func() (learn.cpp:20)
==28876== by 0x108884: main (learn.cpp:31)
==28876== Address 0x5aebc8c is 2 bytes after a block of size 10 alloc'd
==28876== at 0x4C2DC6F: operator new[](unsigned long) (vg_replace_malloc.c:423)
==28876== by 0x1087FB: func() (learn.cpp:17)
==28876== by 0x108884: main (learn.cpp:31)
==28876==
==28876== Invalid write of size 1 <-- 无效写,因为写了已经释放的内存
==28876== at 0x108863: func() (learn.cpp:24)
==28876== by 0x108884: main (learn.cpp:31)
==28876== Address 0x5aebc82 is 2 bytes inside a block of size 10 free'd
==28876== at 0x4C2EB0B: operator delete[](void*) (vg_replace_malloc.c:621) <-- 内存释放
==28876== by 0x10885A: func() (learn.cpp:22)
==28876== by 0x108884: main (learn.cpp:31)
==28876== Block was alloc'd at
==28876== at 0x4C2DC6F: operator new[](unsigned long) (vg_replace_malloc.c:423) <-- 内存申请
==28876== by 0x1087FB: func() (learn.cpp:17)
==28876== by 0x108884: main (learn.cpp:31)
==28876==
==28876== Invalid free() / delete / delete[] / realloc() <-- 无效释放, 重复释放
==28876== at 0x4C2EB0B: operator delete[](void*) (vg_replace_malloc.c:621)
==28876== by 0x108878: func() (learn.cpp:26)
==28876== by 0x108884: main (learn.cpp:31)
==28876== Address 0x5aebc80 is 0 bytes inside a block of size 10 free'd
==28876== at 0x4C2EB0B: operator delete[](void*) (vg_replace_malloc.c:621)
==28876== by 0x10885A: func() (learn.cpp:22)
==28876== by 0x108884: main (learn.cpp:31)
==28876== Block was alloc'd at
==28876== at 0x4C2DC6F: operator new[](unsigned long) (vg_replace_malloc.c:423)
==28876== by 0x1087FB: func() (learn.cpp:17)
==28876== by 0x108884: main (learn.cpp:31)
==28876==
==28876==
==28876== HEAP SUMMARY:
==28876== in use at exit: 20 bytes in 1 blocks
==28876== total heap usage: 3 allocs, 3 frees, 72,734 bytes allocated
==28876==
==28876== 20 bytes in 1 blocks are definitely lost in loss record 1 of 1
==28876== at 0x4C2DC6F: operator new[](unsigned long) (vg_replace_malloc.c:423)
==28876== by 0x108809: func() (learn.cpp:17)
==28876== by 0x108884: main (learn.cpp:31)
==28876==
==28876== LEAK SUMMARY:
==28876== definitely lost: 20 bytes in 1 blocks
==28876== indirectly lost: 0 bytes in 0 blocks
==28876== possibly lost: 0 bytes in 0 blocks
==28876== still reachable: 0 bytes in 0 blocks
==28876== suppressed: 0 bytes in 0 blocks
==28876==
==28876== For counts of detected and suppressed errors, rerun with: -v
==28876== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 0 from 0)
总的来说,使用上还是挺简单的,并且效果不凡。
不过需要注意的地方是,本身检测就需要多运行几次,而多加参数也会增加次数,对于大程序需要注意。