2009년 12월 14일 월요일

Dtrace를 이용한 솔라리스 메모리 누수(memory leak) 잡기

참조 문헌

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 --------------------------------------------

댓글 없음:

댓글 쓰기