간혹가다 메모리 관련 문제를 만났는데 쓸만한 디버깅 툴이 없을 때가 있다. 가령 valgrind 같은 툴은 최신 버전의 Mac OS X에서는 컴파일이 되질 않는다. 이런 문제를 만났을 때에는 해결 방법이 묘연하다. 동적으로 할당된 메모리가 중복 해제되지는 않는지 정도만 알 수 있으면 좋겠는데, 그런 문제도 gdb로는 추적하기가 좀 난감하다.
그런 경우, 다음과 같은 매크로를 만들어 두면 도움이 될 수도 있다. debug.h 코드를 보자.
#ifdef _DEBUG_MEMORY
#define NEW(TYPE,...) (new(__FILE__, __LINE__) TYPE(__VA_ARGS__))
#define NEW_ARR(TYPE,SIZE) (new(__FILE__, __LINE__) TYPE[SIZE])
#define DEL(OBJ) do { \
printf("DLLOC %s %d %p\n", __FILE__,__LINE__, OBJ); \
delete OBJ; \
} while ( false )
#define DEL_ARR(OBJ) do { \
printf("DLLOC %s %d %p\n", __FILE__,__LINE__, OBJ); \
delete[] OBJ; \
} while ( false )
#endif
이 메크로가 정상적으로 동작하기 위해서는 다음과 같은 overloading된 global new 오퍼레이터들이 필요하다.
// memory.h
#ifdef _DEBUG_MEMORY
void* operator new(size_t sz, const char* file, int line) throw (std::bad_alloc);
void* operator new[](size_t sz, const char* file, int line) throw (std::bad_alloc);
#endif
//memory.cpp
#include <stdio.h>
#include "memory.h"
void* operator new(size_t sz, const char* file, int line) throw (bad_alloc)
{
void* p = ::operator new(sz);
printf("ALLOC %s %d %p\n", file, line, p);
return p;
}
void* operator new[](size_t sz, const char* file, int line) throw (bad_alloc)
{
void* p = ::operator new[](sz);
printf("ALLOC %s %d %p\n", file, line, p);
return p;
}
이 코드들을 섞어서 돌리면 컴파일시 _DEBUG_MEMORY 메크로가 정의되어 있을 때 ALLOC, DLLOC 등이 포함된 디버그 아웃풋이 화면에 쏟아진다. 여러분이 작성한 코드의 실행파일이 a.out이라고 할 때, 그 디버그 아웃풋을 다음과 같이 파일에 저장하자.
a.out > a.out.e
이 파일에 포함된 디버그 아웃풋 가운데 LLOC이 포함되어 있는 것만 따로 a.out.memory에 저장한다.
grep LLOC a.out.e > a.out.memory
이 파일을 분석하기 위한 ruby 스크립트를 다음과 같이 작성한다. (파일 이름을 인자로 받을 수도 있어야 하는데 귀찮아서.. ㅋㅋ)
#!/usr/bin/ruby
class AllocInfo
# list of dealloc entries
def initialize(args)
@file, @line, @address = args[:file], args[:line], args[:address]
@deallocer = []
end
def mark_dealloc(entry)
@deallocer << entry
return @deallocer.length
end
def is_deallocated?
return ( @deallocer.length > 0 )
end
attr_reader :file, :line, :address, :deallocer
end
#
# main
#
alloc_list = []
alloc_hash = {}
File.open( "a.out.memory" ) do |f|
f.each_line do |l|
array = l.split()
if array[0] == "ALLOC"
alloc_info = AllocInfo.new(
:file => array[1],
:line => array[2],
:address => array[3]
)
alloc_list << alloc_info
alloc_hash[ array[3] ] = alloc_info
else
entry = alloc_hash.fetch( array[3], nil );
if entry == nil && array[3].to_i != 0
printf "unallocated memory is freed by %s %s %s \n",
array[1], array[2], array[3]
elsif entry != nil
len = entry.mark_dealloc( alloc_info )
if len > 1
printf "MULTIPLE DEALLOCATION===================="
entry.deallocer.each do |d|
printf "%s %s %s", array[1], array[2], array[3]
end
printf "MULTIPLE DEALLOCATION--------------------"
end
end
end
end
alloc_list.each do |e|
unless e.is_deallocated?
printf "not deallocated: %s %s %s\n", e.file, e.line, e.address
end
end
end
이렇게 하면 할당되었는 데 해제되지 않은 메모리나, 두 번 이상 해제된 메모리에 관한 정보를 화면에 찍어준다. 쓸만한 메모리 디버깅 툴이 없을 때 써 볼 만 하다.
'Languages > C++' 카테고리의 다른 글
| MSVCP100D.dll (0) | 2011/02/17 |
|---|---|
| [C/C++] 쓸만한 메모리 디버깅 툴이 없을 떄 (0) | 2010/07/13 |
| cgdb : 텍스트 기반의 gdb 인터페이스 (0) | 2007/12/18 |
| VI와 ctags (0) | 2007/12/18 |
| empty container의 반환 (0) | 2007/12/14 |
| 메모리 할당과 초기화는 다르다 (2) | 2007/12/14 |
댓글을 달아 주세요