您的位置:首页 > 运维架构 > Linux

Linux内存管理——valgrind 分享

2011-06-15 10:07 218 查看
卡卡说:要想搞测试,内存管理得
精!Linux下我们选择Valgrind!

先来个感性认识吧:)

程序示例:test3.cpp

1 #include <stdio.h>

2 #include
<stdlib.h>
3
4 void f(void)

5 {

6 int *x =(int *)
malloc(10*sizeof(int));

7 x[10] = 0;

8 }
9
10 int main()

11 {

12 f();

13 return
0;

14 }

编译链接该程序:
[root@p12 wangjia]# g++ -o test3 -ggdb test3.cpp
使用valgrind检查内存的调试信息:
[root@p12 wangjia]# valgrind --tool=memcheck
--leak-check=full --show-reachable=yes ./test3

==2866== Memcheck, a
memory error detector.

==2866== Copyright (C) 2002-2006, and GNU
GPL'd, by Julian Seward et al.

==2866== Using LibVEX rev 1606, a
library for dynamic binary translation.

==2866== Copyright (C)
2004-2006, and GNU GPL'd, by OpenWorks LLP.

==2866== Using
valgrind-3.2.0, a dynamic binary instrumentation framework.

==2866==
Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.

==2866==
For more details, rerun with: -v

==2866==

==2866== Invalid write
of size 4

==2866== at 0x80483BF: f() (test3.cpp:7) //错误一:数组越界 +
错误位置

==2866== by 0x80483E8: main (test3.cpp:12)

==2866==
Address 0x4252050 is 0 bytes after a block of size 40 alloc'd

==2866==
at 0x401A6D6: malloc (vg_replace_malloc.c:149)

==2866== by
0x80483B5: f() (test3.cpp:6)

==2866== by 0x80483E8: main
(test3.cpp:12)

==2866==

==2866== ERROR SUMMARY: 1 errors from 1
contexts (suppressed: 18 from 1)

==2866== malloc/free: in use at
exit: 40 bytes in 1 blocks. //malloc 和 free 的使用情况

==2866==
malloc/free: 1 allocs, 0 frees, 40 bytes allocated. //错误二:没有释放

==2866==
For counts of detected errors, rerun with: -v

==2866== searching for
pointers to 1 not-freed blocks.

==2866== checked 104,552 bytes.

==2866==

==2866==

==2866== 40 bytes in 1 blocks are definitely lost in
loss record 1 of 1

==2866== at 0x401A6D6: malloc
(vg_replace_malloc.c:149)

==2866== by 0x80483B5: f()
(test3.cpp:6) //错误二所在位置

==2866== by 0x80483E8: main
(test3.cpp:12)

==2866==

==2866== LEAK SUMMARY:

==2866==
definitely lost: 40 bytes in 1 blocks.

==2866== possibly lost: 0
bytes in 0 blocks.

==2866== still reachable: 0 bytes in 0 blocks.

==2866==
suppressed: 0 bytes in 0 blocks.
下面介绍下Valgrind:


Valgrind是
x86架构Linux上的多重用途代码剖析和内存调试工具。但它的主要功能还是对内存的调试,而且它的默认工具也是启动
memcheck。你可以在它的环境中运行你的程序来监视内存的使用情况,比如C 语言中的malloc和free或者 C++中的new和
delete。使用Valgrind的工具包,你可以自动的检测许多内存管理和线程的bug,避免花费太多的时间在bug寻找上,使得你的程序更加稳固。

一、Valgrind的主要功能(结合memcheck工具)

1,使用未初始化的内存 (Use of uninitialised memory)

2,使用已经释放了的内存 (Reading/writing memory after it has been free'd)

3,使用超过 malloc分配的内存空间(Reading/writing off the end of malloc'd
blocks)

4,对堆栈的非法访问 (Reading/writing inappropriate areas on the stack)

5,申请的空间是否有释放 (Memory leaks -- where pointers to malloc'd blocks
are lost forever)

6, malloc/free/new/delete申请和释放内存的匹配(Mismatched use of
malloc/new/new [] vs free/delete/delete [])

7, src和dst的重叠(Overlapping src and dst pointers in memcpy() and
related functions)

二、Valgrind下载与安装

下载地址:http://download.chinaunix.net/download/0011000/10928.shtml

安装:

1)解压valgrind-3.2.0.tar.bz2

$bunzip2
valgrind-3.2.0.tar.bz2

$tar vfx valgrind-3.2.0.tar

2)解压后生成一个 valgrind-3.2.0目录

$cd valgrind-3.2.0

3)编译安装valgrind

$./configure

$make &&
make install

到这里valgrind就编译安装完成。

三、Valgrind使用参数

内存泄漏是最难发现的常
见错误之一,因为除非用完内存或调用
malloc

败,否则都不会导致任何问题。实际上,使用像
C

C++
这类没有垃圾回收机制的语言时,你一大半的时间都花费在处理如何
正确释放内存上。如果程序运行时间足够长,一个小小的失误也会对程序造成重大的影响。

Valgrind
支持很多工具
:memcheck

addrcheck

cachegrind

massif

helgrind

callgrind
等。在运行
Valgrind
时,你必须指明想用的工具。如
$valgrind

tool=memcheck test
,将对
test
进行内存使用情况进行分析,包括
malloc/free/new/new[]/delete


如果没有其它参数,
Valgrind
在程序结束后给出关于
free/delete

malloc/new


共调用次数的简报。

Valgrind
使用参数

--log-fd=N

默认情况下,
输出信息是到标准错误
stderr
,也可以
通过—
log-fd=8
,输出到描述符为
8
的文件

--log-file=filename
将输出的信息
写入到
filename.PID
的文件里,
PID
是运行程序的进行
ID
。可以通过
--log-file-exactly=filename
指定就输出到
filename
文件。

--log-file-qualifier=,
取得环
境变量的值来做为输出信息的文件名。如


log-file-qualifier=$FILENAME


--log-socket=IP:PORT


可以把输出信息发送到网络中指定的
IP:PORT


--error-limit=no


错误报告的个数据进行限制,默认情况不做限制

--tool= [default: memcheck]

--tool=memcheck
:要求用

memcheck
这个工具对程序进行分析

--leak-ckeck=yes


求对
leak
给出详细信息

--leak-check=full
指的
是完全检查内存泄漏

--trace-children= [default: no]

跟踪到子进程里去,默认请况不跟踪

--xml= [default: no]


信息以
xml
格式输出,只有
memcheck
可用

--gen-suppressions= [default: no]

如果为
yes

valgrind
会在每发现一个错误便停下让用户做选择是继续还是

退出更多选项请参看:
http://www.valgrind.org/docs/manual/manual-core.html 可以把一些默
认选项编辑在
~/.valgrindrc

件里。


Valgrind
查找内存泄漏
,
我们必须带上这个参数:

--leak-check= [default: summary]

Leak
是指,存在一块没有被引用的内存空
间,或没有被释放的内存空间,如
summary

只反馈一些总结信息,告诉你有多少个
malloc

多少个
free
等;如果是
full
将输出所有的
leaks
,也就是定位到某一个
malloc/free


--show-reachable= [default: no]

如果为
no
,只输出没有引用的内存
leaks
,或指向
malloc
返回的内存块中部某处的
leaks

--undef-value-errors= [default:
yes]

如果为
yes

memcheck
将对无定义值错进行检查

四、Valgrind要注意的问题

Valgrind


x86
架构上的工具,只能在
Linux
上运行

(FreeBSD

NetBSD
上的相关版本正在开发中

)
。它允许程序员在它的环境里测试程序以检测未配对
malloc
调用
错误和其它使用非法内存
(

未初始化内存
)

错误以及非法内存操作
(
比如同一块内存释放两次或调用不正确的析构函数

)

Valgrind
不检查静态分配数组的使用情况。

五、错误分析(from other points——to be the references)

1.默认使用工具memcheck

2.输出到XML文件:valgrind --leak-check=full --xml=yes --log-file="log.xml"
myprog arg1 arg2

3.错误解释

3.1Illegal read / Illegal write errors

例如:

Invalid read of size 4


at 0x40F6BBCC: (within
/usr/lib/libpng.so.2.1.0.9)

by 0x40F6B804: (within
/usr/lib/libpng.so.2.1.0.9)

by 0x40B07FF4: read_png_image(QImageIO
*) (kernel/qpngio.cpp:326)

by 0x40AC751B: QImageIO::read()
(kernel/qimage.cpp:3621)

Address 0xBFFFF0E0 is not stack'd, malloc'd
or free'd

这个错误的发生是因为对一些memcheck猜想不应该访问的内存进行了读写。

3.2 Use of uninitialised values例如:

Conditional jump or move depends on uninitialised value
(s)

at 0x402DFA94: _IO_vfprintf (_itoa.h:49)

by 0x402E8476:
_IO_printf (printf.c:36)

by 0x8048472: main (tests/manuel1.c:8)


个错误的发生是因为使用了未初始化的数据。一般情况下有两种情形容易出现这个错误:

程序中的局部变量未初始化;

C语言malloc的内存
未初始化;C++中new的对象其成员未被初始化。

3.3 Illegal frees

例如:

Invalid
free()

at 0x4004FFDF: free (vg_clientmalloc.c:577)

by
0x80484C7: main (tests/doublefree.c:10)

Address 0x3807F7B4 is 0
bytes inside a block of size 177 free'd

at 0x4004FFDF: free
(vg_clientmalloc.c:577)

by 0x80484C7: main (tests/doublefree.c:10)

3.4
When a block is freed with an inappropriate deallocation function


如:

Mismatched free() / delete / delete []

at 0x40043249: free
(vg_clientfuncs.c:171)

by 0x4102BB4E: QGArray::~QGArray(void)
(tools/qgarray.cpp:149)

by 0x4C261C41: PptDoc::~PptDoc(void)
(include/qmemarray.h:60)

by 0x4C261F0E: PptXml::~PptXml(void)
(pptxml.cc:44)

Address 0x4BB292A8 is 0 bytes inside a block of size
64 alloc'd

at 0x4004318C: operator new[](unsigned int)
(vg_clientfuncs.c:152)

by 0x4C21BC15: KLaola::readSBStream(int)
const (klaola.cc:314)

by 0x4C21C155:
KLaola::stream(KLaola::OLENode const *) (klaola.cc:416)

by
0x4C21788F: OLEFilter::convert(QCString const &) (olefilter.cc:272)

If
allocated
with malloc, calloc, realloc, valloc or memalign, you must
deallocate with free.If allocated with new[], you must deallocate with
delete[].If allocated with new, you must deallocate with
delete.linux系统对上述错误可能不在意,但是移值到其他平台时却会有问题。

3.5 Passing system call parameters with inadequate read/write
permissions

例如:

Syscall param write(buf) points to uninitialised
byte(s)

at 0x25A48723: __write_nocancel (in
/lib/tls/libc-2.3.3.so)

by 0x259AFAD3: __libc_start_main (in
/lib/tls/libc-2.3.3.so)

by 0x8048348: (within
/auto/homes/njn25/grind/head4/a.out)

Address 0x25AB8028 is 0 bytes
inside a block of size 10 alloc'd

at 0x259852B0: malloc
(vg_replace_malloc.c:130)

by 0x80483F1: main (a.c:5)

Syscall param exit(error_code) contains uninitialised byte(s)

at 0x25A21B44: __GI__exit (in /lib/tls/libc-2.3.3.so)

by
0x8048426: main (a.c:8)

Memcheck检查所有的被系统调用的参数。

It checks all the
direct parameters themselves.

Also, if a system call needs to read from a buffer provided by your
program, Memcheck checks that the entire buffer is addressable and has
valid data, ie, it is readable.

Also, if the system call needs to write to a user-supplied
buffer, Memcheck checks that the buffer is addressable.

例如:

#include
<stdlib.h>

#include <unistd.h>

int main( void )

{

char*
arr = malloc(10);

int* arr2 = malloc(sizeof(int));

write( 1 /*
stdout */, arr, 10 );

exit(arr2[0]);

}

错误信息:

Syscall param
write(buf) points to uninitialised byte(s)

at 0x25A48723:
__write_nocancel (in /lib/tls/libc-2.3.3.so)

by 0x259AFAD3:
__libc_start_main (in /lib/tls/libc-2.3.3.so)

by 0x8048348: (within
/auto/homes/njn25/grind/head4/a.out)

Address 0x25AB8028 is 0 bytes
inside a block of size 10 alloc'd

at 0x259852B0: malloc
(vg_replace_malloc.c:130)

by 0x80483F1: main (a.c:5)

Syscall param
exit(error_code) contains uninitialised byte(s)

at 0x25A21B44:
__GI__exit (in /lib/tls/libc-2.3.3.so)

by 0x8048426: main (a.c:8)


递了无效参数到系统函数中。

3.6 Overlapping source and destination blocks

C的以下库函数拷贝数据从一块内存到另一块
内存时: memcpy(), strcpy(), strncpy(), strcat(), strncat(). 源和目的都不允许溢出。


如:

==27492== Source and destination overlap in memcpy(0xbffff294,
0xbffff280, 21)

==27492== at 0x40026CDC: memcpy
(mc_replace_strmem.c:71)

==27492== by 0x804865A: main
(overlap.c:40)

3.7 Memory leak detection

错误信息:

Still reachable: A pointer to the start of the block is
found. This usually indicates programming sloppiness. Since the block
is still pointed at, the programmer could, at least in principle, free
it before program exit. Because these are very common and arguably not
a problem, Memcheck won't report such blocks unless
--show-reachable=yes is specified.

Possibly lost, or "dubious": A
pointer to the interior of the block is found. The pointer might
originally have pointed to the start and have been moved along, or it
might be entirely unrelated. Memcheck deems such a block as "dubious",
because it's unclear whether or not a pointer to it still exists.

Definitely
lost, or "leaked": The worst outcome is that no pointer to the block
can be found

[ps]:其中--leak-check=full
指的是完全检查内存泄漏,--show-reachable=yes是显示内存泄漏的地点,--trace-children=yes是跟入子进程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: