C/C++的内存泄漏检测工具Valgrind memcheck的使用经历(求大神解答疑惑,找出内存泄露真凶)(二)
RROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
复制代码
首先从“All heap blocks were freed -- no leaks are possible”可以看出上面的释放操作的确是正确的,而不是有些人认为的delete d;只会释放d[]的第一个元素的空间,后面的都不会得到释放。但是从“Mismatched free() / delete / delete []”知道Valgrind实际上是不允许这样操作的,虽然没有内存泄露问题,但是new[]与delete不匹配,这样的
编程风格不经意间就容易犯低级错误,所以Valgrind报错了,但是我想Valgrind内部实现应该不会考虑的这么复杂,它就检查new是否与delete配对,new[]是否与delete[]配对,而不管有时候new[]与delete配对也不会出现问题的。
综上所述,给我的经验就是:在某些情况下,new[]分配的内存用delete不会出错,但是大多情况下会产生严重的内存问题,所以一定要养成将new和delete,new[]和delete[]配套使用的良好编程习惯。
2. 最看不懂的错误:一堆看不懂的Invalid read/write错误
比如下面这样一个程序:
复制代码
#include
#include
#include
struct accept_pair {
bool is_accept_state;
bool is_strict_end;
char app_name[0];
};
int main() {
char *s = "Alexia";
accept_pair *ap = (accept_pair*)malloc(sizeof(accept_pair) + sizeof(s));
strcpy(ap->app_name, s);
printf("app name: %s\n", ap->app_name);
free(ap);
return 0;
}
复制代码
首先对该程序做个扼要的说明:
这里结构体里定义零长数组的原因在于我的需求:我在其它地方要用到很大的accept_pair数组,其中只有个别accept_pair元素中的app_name是有效的(取决于某些值的判断,如果为true才给app_name赋值,如果为false则app_name无意义,为空),因此若是char app_name[20],那么大部分accept_pair元素都浪费了这20个字节的空间,所以我在这里先一个字节都不分配,到时谁需要就给谁分配,遵循“按需分配”的古老思想。可能有人会想,用char *app_name也可以啊,同样能实现按需分配,是的,只是多4个字节而已,属于替补方法。
在g++下经过测试,没有什么问题,能够正确运行,但用Valgrind检测时却报出了一些错误,不是内存泄露问题,而是内存读写错误:
复制代码
==3511== Memcheck, a memory error detector
==3511== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==3511== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==3511== Command: ./zero
==3511==
==3511== Invalid write of size 1
==3511== at 0x402CD8B: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3511== by 0x80484E3: main (in /home/hadoop/test/zero)
==3511== Address 0x420002e is 0 bytes after a block of size 6 alloc'd
==3511== at 0x402C418: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3511== by 0x80484C8: main (in /home/hadoop/test/zero)
==3511==
==3511== Invalid write of size 1
==3511== at 0x402CDA5: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3511== by 0x80484E3: main (in /home/hadoop/test/zero)
==3511== Address 0x4200030 is 2 bytes after a block of size 6 alloc'd
==3511== at 0x402C418: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3511== by 0x80484C8: main (in /home/hadoop/test/zero)
==3511==
==3511== Invalid read of size 1
==3511== at 0x40936A5: vfprintf (vfprintf.c:1655)
==3511== by 0x409881E: printf (printf.c:34)
==3511== by 0x4063934: (below main) (libc-start.c:260)
==3511== Address 0x420002e is 0 bytes after a block of size 6 alloc'd
==3511== at 0x402C418: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3511== by 0x80484C8: main (in /home/hadoop/test/zero)
==3511==
==3511== Invalid read of size 1
==3511== at 0x40BC3C0: _IO_file_xsputn@@GLIBC_2.1 (fileops.c:1311)
==3511== by 0x4092184: vfprintf (vfprintf.c:1655)
==3511== by 0x409881E: printf (printf.c:34)
==3511== by 0x4063934: (below main) (libc-start.c:260)
==3511== Address 0x420002f is 1 bytes after a bl