참조 문헌
Dtrace를 이용한 메모리 누수 잡는 법을 소개하고자 한다.
아래 사용한 스크립트는 5번 항목 또는 위의 링크를 참조하도록 한다.
1. 메모리 leak을 유발하는 코드 작성
#include
int main(void)
{
char *test1;
while(1)
{
test1 = malloc(sizeof(char) * 256);
printf("memory leak\n");
sleep(1);
}
return 1;
}
2. 해당 프로그램 실행
# a.out
3. dtrace로 memory malloc과 free한 부분을 찾음
사용법
# ./memleak.d PID > output
사용 예
# su -
# pgrep a.out
5659
# ./memleak.d 5659 > leak.data
Ctrl+c
4. 스크립트로 malloc과 free를 매칭해서 제대로 free가 되지 않은 부분을 추출해 냄
사용법
./findleaks.pl output
사용예
./findleaks.pl leak.data
Ptr=0x22018 Size=256
libc.so.1`malloc+0x6c
a.out`main+0x8
a.out`_start+0x5c
---------
Ptr=0x21af0 Size=256
libc.so.1`malloc+0x6c
a.out`main+0x8
a.out`_start+0x5c
---------
Ptr=0x21e08 Size=256
libc.so.1`malloc+0x6c
a.out`main+0x8
a.out`_start+0x5c
---------
Ptr=0x21d00 Size=256
libc.so.1`malloc+0x6c
a.out`main+0x8
a.out`_start+0x5c
---------
Ptr=0x21bf8 Size=256
libc.so.1`malloc+0x6c
a.out`main+0x8
a.out`_start+0x5c
---------
Ptr=0x21f10 Size=256
libc.so.1`malloc+0x6c
a.out`main+0x8
a.out`_start+0x5c
5. 스크립트
1)
# cat ./memleak.d
-------------------------------------- cut --------------------------------------------
#!/usr/sbin/dtrace -s
pid$1:libc.so.1:malloc:entry
{
self->trace = 1;
self->size = arg0;
}
pid$1:libc.so.1:malloc:return
/self->trace == 1/
{
printf("Ptr=0x%p Size=%d", arg1, self->size);
ustack();
self->trace = 0;
self->size = 0;
}
pid$1:libc.so.1:realloc:entry
{
self->trace = 1;
self->size = arg1;
self->oldptr = arg0;
}
pid$1:libc.so.1:realloc:return
/self->trace == 1/
{
printf("Ptr=0x%p Oldptr=0x%p Size=%d", arg1, self->oldptr, self->size);
ustack();
self->trace = 0;
self->size = 0;
}
pid$1:libc.so.1:calloc:entry
/self->trace == 1/
{
self->trace = 1;
self->size = arg1;
}
pid$1:libc.so.1:calloc:return
/self->trace == 1/
{
printf("Ptr=0x%p Size=%d", arg1, self->size);
ustack();
self->trace = 0;
self->size = 0;
}
pid$1:libc.so.1:free:entry
{
printf("Ptr=0x%p ", arg0);
}
-------------------------------------- cut --------------------------------------------
2)
# cat findleaks.pl
-------------------------------------- cut --------------------------------------------
#!/usr/bin/perl
use Data::Dumper;
my %hash = ();
while (<>) {
if ((/malloc:return Ptr=([^ ]*) Size=(.*)/) ||
(/calloc:return Ptr=([^ ]*) Size=(.*)/)) {
$hash{$1} = { size => $2 };
while (<>) {
last if /^$/;
$hash{$1}->{stack} .= $_;
}
}
elsif (/free:entry Ptr=([^ ]*)/) {
if (exists $hash{$1} and $hash{$1}) {
$hash{$1} = '';
}
}
elsif (/realloc:entry Ptr=([^ ]*) Oldptr=([^ ]*) Size=(.*)/) {
if ($1 eq $2) {
if (exists $hash{$1} and $hash{$1}) {
$hash{$1} = { size => $3 };
$hash{$1}->{stack} = '';
while (<>) {
last if /^$/;
$hash{$1}->{stack} .= $_;
}
}
} else {
$hash{$1} = '';
$hash{$2}= { size => $3 };
$hash{$2}->{stack} = '';
while (<>) {
last if /^$/;
$hash{$2}->{stack} .= $_;
}
}
}
}
foreach my $key (keys %hash) {
next if not $hash{$key}->{size};
print "Ptr=$key Size=", $hash{$key}->{size}, "\n";
print $hash{$key}->{stack}, "\n---------\n";
}
-------------------------------------- cut --------------------------------------------
댓글 없음:
댓글 쓰기