valgrind简介和使用

概述

最近有需求要分析定位下开发的文件存储网关的内存泄露问题,对比了几款后选择了valgrind这款工具,功能很是强大,这里我还只使用了一些基本的功能,记录如下。

Valgrind支持很多工具: MemcheckAddrcheckCachegrindMassifHelgrindCallgrind等。

官网:http://valgrind.org/

安装

1
2
3
4
5
6
7
$ wget ftp://sourceware.org/pub/valgrind/valgrind-3.13.0.tar.bz2
$ bzip2 -d valgrind-3.13.0.tar.bz2
$ tar -xf valgrind-3.13.0.tar
$ cd valgrind-3.13.0/
$ ./configure
$ make
$ sudo make install

使用与分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ valgrind --help
usage: valgrind [options] prog-and-args
...

常用的一些options有:
--trace-children=no|yes Valgrind-ise child processes (follow execve)? [no]
--log-file=<file> log messages to <file>
--leak-check=no|summary|full search for memory leaks at exit? [summary]

--show-reachable=yes same as --show-leak-kinds=all
--show-reachable=no --show-possibly-lost=yes
same as --show-leak-kinds=definite,possible
--show-reachable=no --show-possibly-lost=no
same as --show-leak-kinds=definite

常用命令格式:

1
$ /usr/local/bin/valgrind --log-file=mylog ./file-gateway

valgrindmemcheck组件支持的内存泄露检查大概有:

  1. 读写非法的内存
  2. 访问未初始化的内存
  3. 访问已经释放了的内存
  4. 申请的内存没有释放
  5. 重复释放内存
  6. 释放非法内存
  7. sourcedestination内存的重叠

uninitialised byte(s)

检查出程序中未初始化而访问的变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
==1350634== Thread 14:
==1350634== Syscall param setxattr(value) points to uninitialised byte(s)
==1350634== at 0x6D9EB8A: setxattr (in /usr/lib64/libc-2.17.so)
==1350634== by 0x487268: VFS::file_setxattr(std::string, std::string, void*, int) (vfs.cc:64)
==1350634== by 0x488066: FileGwVFS::file_setxattr(std::string, std::string, void*, int) (vfs.cc:175)
==1350634== by 0x459583: FileGateway::set_file_xattr(std::string, sgwd_xattr*) (file_gateway.cc:742)
==1350634== by 0x463706: FileGwRedisWorkItem::update_file_xattr_status(gateway_file_status) (redis_work_item.cc:703)
==1350634== by 0x4641B1: FileGwRedisWorkItem::file_upload() (redis_work_item.cc:793)
==1350634== by 0x45F89E: FileGwRedisWorkItem::process() (redis_work_item.cc:190)
==1350634== by 0x486532: WorkThread::process_work_item() (work_thread.cc:49)
==1350634== by 0x486850: ShardedWorkThread::entry() (work_thread.cc:112)
==1350634== by 0x481B58: Thread::_entry_func(void*) (thread.cc:74)
==1350634== by 0x4E3DDC4: start_thread (in /usr/lib64/libpthread-2.17.so)
==1350634== by 0x6D9FCEC: clone (in /usr/lib64/libc-2.17.so)
==1350634== Address 0x115d95a4 is on thread 14's stack
==1350634== in frame #4, created by FileGwRedisWorkItem::update_file_xattr_status(gateway_file_status) (redis_work_item.cc:697)
1
2
3
4
5
6
7
8
9
==1350634== Thread 19:
==1350634== Conditional jump or move depends on uninitialised value(s)
==1350634== at 0x465155: FileGwRedisWorkItem::callback(void*) (redis_work_item.cc:946)
==1350634== by 0x481021: FileGwS3WorkItem::postProcess() (s3_work_item.cc:244)
==1350634== by 0x486551: WorkThread::process_work_item() (work_thread.cc:50)
==1350634== by 0x48666E: WorkThread::entry() (work_thread.cc:78)
==1350634== by 0x481B58: Thread::_entry_func(void*) (thread.cc:74)
==1350634== by 0x4E3DDC4: start_thread (in /usr/lib64/libpthread-2.17.so)
==1350634== by 0x6D9FCEC: clone (in /usr/lib64/libc-2.17.so)

Invalid read/write

读取非法地址,通常是继续访问释放后的内存空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
==1346085== Thread 14:
==1346085== Invalid read of size 4
==1346085== at 0x4E40BB0: pthread_mutex_unlock (in /usr/lib64/libpthread-2.17.so)
==1346085== by 0x4559FC: __gthread_mutex_unlock(pthread_mutex_t*) (gthr-default.h:778)
==1346085== by 0x45B6C1: std::mutex::unlock() (mutex:152)
==1346085== by 0x489CA8: std::lock_guard<std::mutex>::~lock_guard() (mutex:420)
==1346085== by 0x4895BB: WorkItemCompletion::finish() (thread_work_item.cc:47)
==1346085== by 0x48971E: ThreadWorkItem::postProcess() (thread_work_item.cc:70)
==1346085== by 0x45F721: RedisWorkItem::postProcess() (redis_work_item.cc:139)
==1346085== by 0x45FFED: FileGwRedisWorkItem::postProcess() (redis_work_item.cc:234)
==1346085== by 0x486761: WorkThread::process_work_item() (work_thread.cc:50)
==1346085== by 0x486A60: ShardedWorkThread::entry() (work_thread.cc:112)
==1346085== by 0x481D68: Thread::_entry_func(void*) (thread.cc:74)
==1346085== by 0x4E3DDC4: start_thread (in /usr/lib64/libpthread-2.17.so)
==1346085== Address 0xabd3788 is 24 bytes inside a block of size 88 free'd
==1346085== at 0x4C2B1CD: operator delete(void*) (vg_replace_malloc.c:576)
==1346085== by 0x489253: WorkItemCompletion::~WorkItemCompletion() (thread_work_item.cc:29)
==1346085== by 0x4572E4: FileGateway::issue_filegw_redis_workitem(FileOp*, FileInfo*, bool, bool, void (*)(void*), void*) (file_gateway.cc:298)
==1346085== by 0x457D31: FileGateway::do_read(FileOp*) (file_gateway.cc:455)
==1346085== by 0x455298: GatewayWorkItem::process() (gateway_work_item.cc:74)
==1346085== by 0x486742: WorkThread::process_work_item() (work_thread.cc:49)
==1346085== by 0x48687E: WorkThread::entry() (work_thread.cc:78)
==1346085== by 0x481D68: Thread::_entry_func(void*) (thread.cc:74)
==1346085== by 0x4E3DDC4: start_thread (in /usr/lib64/libpthread-2.17.so)
==1346085== by 0x6D9FCEC: clone (in /usr/lib64/libc-2.17.so)
==1346085== Block was alloc'd at
==1346085== at 0x4C2A243: operator new(unsigned long) (vg_replace_malloc.c:334)
==1346085== by 0x457171: FileGateway::issue_filegw_redis_workitem(FileOp*, FileInfo*, bool, bool, void (*)(void*), void*) (file_gateway.cc:286)
==1346085== by 0x457D31: FileGateway::do_read(FileOp*) (file_gateway.cc:455)
==1346085== by 0x455298: GatewayWorkItem::process() (gateway_work_item.cc:74)
==1346085== by 0x486742: WorkThread::process_work_item() (work_thread.cc:49)
==1346085== by 0x48687E: WorkThread::entry() (work_thread.cc:78)
==1346085== by 0x481D68: Thread::_entry_func(void*) (thread.cc:74)
==1346085== by 0x4E3DDC4: start_thread (in /usr/lib64/libpthread-2.17.so)
==1346085== by 0x6D9FCEC: clone (in /usr/lib64/libc-2.17.so)

SUMMARY

valgrind最后会有内存分析的总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
==1366931== HEAP SUMMARY:
==1366931== in use at exit: 41,110 bytes in 1,019 blocks
==1366931== total heap usage: 1,275,222 allocs, 1,274,203 frees, 334,495,820 bytes allocated
==1366931==
==1366931== LEAK SUMMARY:
==1366931== definitely lost: 11,632 bytes in 191 blocks
==1366931== indirectly lost: 80 bytes in 2 blocks
==1366931== possibly lost: 608 bytes in 1 blocks
==1366931== still reachable: 28,790 bytes in 825 blocks
==1366931== of which reachable via heuristic:
==1366931== stdstring : 145 bytes in 4 blocks
==1366931== suppressed: 0 bytes in 0 blocks
==1366931== Rerun with --leak-check=full to see details of leaked memory
==1366931==
==1366931== For counts of detected and suppressed errors, rerun with: -v
==1366931== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

LEAK SUMMARY:内存泄露信息的总结,详细信息从前面的log中查找

  • definitely lost: 肯定丢失的内存,这部分必须处理
  • indirectly lost: 间接丢失的内存,可能是一个structure里指向的内存
  • possibly lost: 可能丢失的部分,这是由于C/C++语言指针处理的特点造成的,可能不太准确
  • still reachable: 程序可能是ok的,可以配置--show-reachable=no不显示这部分

若想显示泄露内存的详细信息,使用参数--leak-check=full

/usr/local/bin/valgrind --leak-check=full --log-file=mylog ./flle-gateway

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
==1373210== HEAP SUMMARY:
==1373210== in use at exit: 30,758 bytes in 843 blocks
==1373210== total heap usage: 405,641 allocs, 404,798 frees, 44,538,821 bytes allocated
==1373210==
==1373210== 608 bytes in 1 blocks are possibly lost in loss record 605 of 613
==1373210== at 0x4C2B9B5: calloc (vg_replace_malloc.c:711)
==1373210== by 0x4011DE4: _dl_allocate_tls (in /usr/lib64/ld-2.17.so)
==1373210== by 0x4E3E960: pthread_create@@GLIBC_2.2.5 (in /usr/lib64/libpthread-2.17.so)
==1373210== by 0x489969: libsgsvc_init (in /home/yangguanjun3/storage-file-gateway/userspace/build/storage-flle-gw)
==1373210== by 0x456B06: FileGateway::init_netlink() (file_gateway.cc:218)
==1373210== by 0x456CA4: FileGateway::init() (file_gateway.cc:234)
==1373210== by 0x4537A2: main (main.cc:79)
==1373210==
==1373210== 1,360 bytes in 17 blocks are definitely lost in loss record 611 of 613
==1373210== at 0x4C29C23: malloc (vg_replace_malloc.c:299)
==1373210== by 0x4785C7: Aws::Utils::Stream::PreallocatedStreamBuf* Aws::New<Aws::Utils::Stream::PreallocatedStreamBuf, Aws::Utils::Array<unsigned char>*, unsigned long>(char const*, Aws::Utils::Array<unsigned char>*&&, unsigned long&&) (AWSMemory.h:70)
==1373210== by 0x473446: S3BackendStorage::put_object_from_file_slice(std::basic_string<char, std::char_traits<char>, Aws::Allocator<char> >, std::basic_string<char, std::char_traits<char>, Aws::Allocator<char> >, std::string const&, unsigned long, unsigned long) (s3_storage.cc:294)
==1373210== by 0x480110: FileGwS3WorkItem::file_upload() (s3_work_item.cc:147)
==1373210== by 0x480C0D: FileGwS3WorkItem::process() (s3_work_item.cc:221)
==1373210== by 0x486316: WorkThread::process_work_item() (work_thread.cc:49)
==1373210== by 0x486452: WorkThread::entry() (work_thread.cc:78)
==1373210== by 0x48193C: Thread::_entry_func(void*) (thread.cc:74)
==1373210== by 0x4E3DDC4: start_thread (in /usr/lib64/libpthread-2.17.so)
==1373210== by 0x6D9FCEC: clone (in /usr/lib64/libc-2.17.so)
==1373210==
==1373210== LEAK SUMMARY:
==1373210== definitely lost: 1,360 bytes in 17 blocks
==1373210== indirectly lost: 0 bytes in 0 blocks
==1373210== possibly lost: 608 bytes in 1 blocks
==1373210== still reachable: 28,790 bytes in 825 blocks
==1373210== of which reachable via heuristic:
==1373210== stdstring : 145 bytes in 4 blocks
==1373210== suppressed: 0 bytes in 0 blocks
==1373210== Reachable blocks (those to which a pointer was found) are not shown.
==1373210== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==1373210==
==1373210== For counts of detected and suppressed errors, rerun with: -v
==1373210== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

参考

http://valgrind.org/docs/manual/manual.html
http://www.oschina.net/translate/valgrind-memcheck
https://www.ibm.com/developerworks/cn/linux/l-cn-valgrind/

支持原创