노무현 대통령 배너


2008. 10. 28. 17:54

디버깅의 도(5)-메모리 관련 문제들

출처: http://www.buggymind.com/114

프로그래밍을 하다가 만나게 되는 문제들 중 상당수가 (특히 C/C++ 프로그래머의 경우) 메모리 문제입니다. 메모리 문제는 찾아내기도 어렵고, 교정하기도 어렵습니다. 잘못된 메모리 사용이 실제 어떤 형태의 현상으로 드러나게 될지를 단언할 수가 없는 탓입니다. 특히 Java같은 언어는 메모리를 할당하는 과정은 프로그래머가 통제할 수 있지만, 메모리를 반환하는 과정은 통제할 수 없기 때문에, 메모리 문제를 발견하기도 어렵고 교정하기는 더더욱 어렵습니다. 그래서 Java 프로그래밍을 하는 와중에 험한 꼴을 당하지 않으려면 Effective Java같은 책을 잘 읽어야 합니다. X-)

C/C++ 프로그래밍 언어의 경우에는 메모리를 조작하는 데 있어 프로그래머가 갖는 자유도가 꽤 큽니다. 그래서 메모리를 엉뚱하게 조작하는 실수를 저지를 확률이 굉장히 높은 편입니다. 그래서 일찍부터 많은 사람들이 'Unix 계열 운영체제에서 C나 C++로 프로그래밍하는 사람들을 위한' 메모리 관련 문제 탐지 기법들을 내놓았습니다. 이런 기법들은 '잘못된 메모리 참조가 발생할 경우 그 사실을 보고해 주는' 형태를 띠고 있으며, 워낙 그런 기법에 대한 수요가 컸기 때문에 그 일부는 이미 운영체제에 붙박이로 제공되고 있기도 합니다.

가령 Linux 같은 경우는 bash 상에서 MALLOC_CHECK_ 환경변수의 값을 1로 만들면 heap curruption이 발생했을 경우 진단 메시지가 화면에 출력되고, 2로 만들면 그 즉시 실행중이던 프로그램이 종료됩니다. 디버깅을 하다보면 heap curruption이 발생하는 시점과 프로그램이 SIGSEGV를 받는 시점이 달라서 디버깅하기 곤란할 때가 있는데, 그런 경우에 유용합니다. 적어도 '잘못된 일이 벌어지는 시점'과 '프로그램이 죽는 시점'을 똑같이 만들 수 있거든요. (printf에 의존적인 디버깅을 하시는 분들께는 이런 기법이 특히 유용하죠.) Solaris의 경우에는 watchmalloc을 사용하여 Linux와 비슷한 효과를 누릴 수 있습니다. 구글에서  man watchmalloc 해보시면 사용법을 아실 수 있으니까 설명은 생략하겠습니다. Linux와 사용법이 크게 다른 편은 아니랍니다.

하지만 뭐니뭐니 해도 메모리 관련 문제를 잡는 가장 좋은 방법은, 좋은 진단 툴을 사용하는 것입니다. 옛날부터 정평이 나 있는 메모리 누수 탐지 툴로는 purify같은 것이 있습니다만, 고가라 선듯 사용하기가 겁나죠. 하지만 Linux에서 프로그래밍을 하고 있다면, valgrind라는 막강한 툴이 있습니다.

valgrind는 -g 옵션을 주고 컴파일된 프로그램이라면 적용될 수 있습니다. 가령 컴파일된 실행파일의 이름이 a.out이라면, 다음과 같이 실행하면 됩니다.

valgrind --tool=memcheck ./a.out

--tool 옵션을 통해 실행 파일에 어떤 문제들이 내재되어 있는지를 살펴볼 수 있습니다. default는 memcheck이며, 메모리 관련 문제들을 검사하겠다는 뜻입니다. 메모리 누수(leak) 현상이 발생하는지의 여부 등을 이 옵션을 통해 검사할 수 있게 됩니다. 그것도 아주 빨리요.

프로그램(위의 경우에는 a.out)의 실행이 끝나면 valgrind는 다음과 같은 형식으로 탐지된 오류를 보고합니다.

==25832== Invalid read of size 4
==25832==    at 0x8048724: BandMatrix::ReSize(int, int, int) (bogon.cpp:45)
==25832==    by 0x80487AF: main (bogon.cpp:66)
==25832==  Address 0xBFFFF74C is not stack'd, malloc'd or free'd
위의 메시지에는 0xBFFFF74C에 대한 잘못된 메모리 참조가 발생했는데, 그 주소가 가리키는 메모리가 정상적으로 스택에 올라간 메모리도 아니고, malloc된 적도 없으며 free된 적도 없다는 것을 알리는 정보가 포함되어 있습니다. 참조가 발생한 위치도 요약되어 있구요.

최신의 Linux 배포판에는 이제 valgrind가 거의 번들되어 배포되고 있는 것 같습니다. 설사 설치되어 있지 않더라도, 요즘은 apt-get이나 yum 등 네트워크를 통해서 자동으로 프로그램을 설치할 수 있는 툴이 잘 정비되어 있으니까, 그 툴들을 사용하면 간단하게 설치해서 돌려볼 수 있습니다.

디버깅을 할 때 거의 아무런 도구를 사용하지 않는 프로그래머를 많이 볼 수 있습니다만, 메모리 관련 오류를 탐지하는 데 있어서는 이런 도구를 사용하는 쪽이 절대적으로 빠릅니다. 특히 오랜 시간 돌려놓으면 비주기적으로 죽어버리곤 하는 프로그램을 디버깅하는 데는 이런 도구를 활용하는 편이 낫죠.

valgrind에 대한 더 자세한 정보를 원하신다면 일단 여기로.

'프로그래밍' 카테고리의 다른 글

distcc: a fast, free distributed C/C++ compiler  (0) 2009.02.06
[1] 64-bit/32-bit 빌드 실습  (1) 2009.01.15
디버깅의 도(4)-GDB  (0) 2008.10.28
디버깅의 도(3)-Assert  (0) 2008.10.28
디버깅의 도(2)  (0) 2008.10.28