红联Linux门户
Linux帮助

使用ltrace定位内存泄漏-Linux

发布时间:2016-08-14 09:19:52来源:topspeedsnail.com作者:斗大的熊猫
ltrace和strace是Linux上常用的调试工具:strace跟踪用户程序的系统调用;ltrace跟踪动态库函数的调用。
本文介绍怎么使用ltrace找到内存泄露-调用了malloc而没有调用对应的free函数释放内存。
 
看下面一段无意义的代码:
#include <stdlib.h>
#include <stdio.h>
int main()
{
char *p = (char*)malloc(1024);
sprintf(p, "%s", "abcde");
printf("%s\n", p);
int *p1 = (int*)malloc(4);
*p1 = 100;
void *p2 = malloc(256);
free(p1);
int a = 2;
printf("%d\n", a);
free(p);
void *p3 = malloc(124);
free(p2);
void *p4 = malloc(23);
free(p4);
return 0;
}
 
使用ltrace调试:
$ ltrace ./a.out 
__libc_start_main(0x4005f6, 1, 0x7ffc2cd65088, 0x4006c0 <unfinished ...>
malloc(1024)                                     = 0x1ae7010
puts("abcde"abcde)                               = 6
malloc(4)                                        = 0x1ae7830
malloc(256)                                      = 0x1ae7850
free(0x1ae7830)                                  = <void>
printf("%d\n", 22)                               = 2
free(0x1ae7010)                                  = <void>
malloc(124)                                      = 0x1ae7010
free(0x1ae7850)                                  = <void>
malloc(23)                                       = 0x1ae70a0
free(0x1ae70a0)                                  = <void>
+++ exited (status 0) +++
 
找到我们关注的malloc和free函数调用:
malloc(1024)                                     = 0x1ae7010
malloc(4)                                        = 0x1ae7830
malloc(256)                                      = 0x1ae7850
free(0x1ae7830)                                  = <void>
free(0x1ae7010)                                  = <void>
malloc(124)                                      = 0x1ae7010
free(0x1ae7850)                                  = <void>
malloc(23)                                       = 0x1ae70a0
free(0x1ae70a0)                                  = <void>
 
简单的跟踪malloc分配内存地址和free释放内存地址就可以找到哪里发生了内存泄露,上面0x1ae7010没有释放(malloc(124))。为了简单我忽略了calloc/realloc。
ltrace并不能直接定位到调用位置,也就是说我们只知道发生了内存泄露。后续你可以选择使用Valgrind(http://valgrind.org/)定位位置,它是内存调试、内存泄漏检测以及性能分析的工具。
 
使用Python脚本分析输出,实现自动检测:
把j结果输出到文件:
$ ltrace -o memlake ./a.out
$ cat memlake 
__libc_start_main(0x4005f6, 1, 0x7fff9caa3138, 0x4006c0 <unfinished ...>
malloc(1024)                                     = 0x152c010
puts("abcde")                                    = 6
malloc(4)                                        = 0x152c830
malloc(256)                                      = 0x152c850
free(0x152c830)                                  = <void>
printf("%d\n", 2)                                = 2
free(0x152c010)                                  = <void>
malloc(124)                                      = 0x152c010
free(0x152c850)                                  = <void>
malloc(23)                                       = 0x152c0a0
free(0x152c0a0)                                  = <void>
+++ exited (status 0) +++
 
Python脚本:
import re
import sys
import shlex
with open(sys.argv[1], 'r') as f:
flines = f.readlines()
lines = filter(lambda x: 'malloc' in x or 'free' in x, flines)
memtable = {}
for line in lines:
tokens = shlex.split(line)
# malloc(size) = addr
if 'malloc' in tokens[0]:
size = re.search(r'malloc\((.*)\)', tokens[0]).group(1)
addr = tokens[2]
memtable[addr] = size
# free(addr) = <void>
elif 'free' in tokens[0]:
addr = re.search(r'free\((.*)\)', tokens[0]).group(1)
memtable.pop(addr, None)
for k, v in memtable.iteritems():
print('leaked', v, 'bytes of memory at', k)
$ python checkmem.py memlake 
('leaked', '124', 'bytes of memory at', '0x152c010')
 
$ python checkmem.py memlake 
('leaked', '124', 'bytes of memory at', '0x152c010')
注意:上面脚本并没有处理calloc和realloc。
 
本文永久更新地址:http://www.linuxdiyf.com/linux/23300.html