Windows에서 개발을 한 경험이 있는 분들이라면, AQTime(예전 이름은 Memproof)이라는 상용 Tool을 잘 아실 것입니다.

AQTime은 Runtime 검사를 통해서 Application의 Performance를 진단하고 Memory Leak(Heap Memory를 할당했을 경우 사용 후에 System에 반환하지 않아서 발생하는 누수현상)을 검사할 수 있는 유명한 Profiling Tool입니다.

이러한 Profiling Tool을 사용하면 개발자가 미처 파악하지 못한 Application의 문제를 해결하고 Performance를 향상시킬 수 있기 때문에 Project의 안정화 시에 주로 사용됩니다.

이번 Post에서는 이와 비슷한 기능을 Linux에서 수행하는 Command-line Tool인 Valgrind를 통해서 Memory Leak을 검사하는 방법을 알아보도록 하겠습니다.

Table of Contents [Show]

1. Valgrind?

Valgrind는 앞서 말한 대로 Linux Program의 Profiling을 위한 Application입니다. (지원하는 Platform과 Architecture를 확인하려면 여기를 방문하면 됩니다.) 그리고 License가 GPL이기 때문에 AQTime과 달리 사용하는데 전혀 비용이 들지 않습니다.

또한 수많은 Open-source Project가 Valgrind를 통해서 Debugging과 Profiling을 수행하고 있다는 것은 이 Program의 정확성과 안정성을 증명합니다.

Valgrind는 엄밀하게 말하면 Profiling Suite로 여러가지 Profiling을 위한 도구를 포함하고 있으며 각각의 도구는 valgrind 명령을 통해 통합되어 수행됩니다. 그 중 일부를 소개하면 다음과 같습니다.

  • Memcheck: Memory 관리의 문제를 진단하는 Tool입니다. 할당받지 않은 Heap Memory에 접근하는 것이나 Memory Leak과 같은 문제를 이 Tool을 통하여 발견할 수 있습니다.
  • Callgrind: Runtime 시에 각 함수의 호출 history와 실행 Function간의 Call Graph를 만들기 위한 정보를 기록하는데 사용하는 도구입니다. 저장된 내용은 Command-line Tool이나 KCachegrind를 통해서 분석할 수 있습니다. KCachegrind에 대해서는 이후에 간단한 사용법을 설명하겠습니다.
  • Massif: Heap Memory에 대한 사용 정보를 확인할 수 있습니다. 간단한 예제와 설명은 여기를 참고하기 바랍니다.
  • Helgrind: POSIX Thread(간단히 PThread)를 Program에서 사용할 때 각 Thread간의 동기화와 관련된 문제를 진단하기 위한 Tool입니다.

Valgrind는 좋은 Tool이지만 사용할 때 유의할 점이 있습니다. Valgrind는 Code 상의 오류를 검사할 수 있지만, 문맥적인 오류는 잡아내지 못합니다. 다시 말하면, 기술적으로 해당 Program이 문제가 없다는 것을 증명할 수는 있지만, 실제 그 Program이 사용자가 원하는 대로 제대로 동작한다는 것을 증명할 수 없다는 것입니다. 생각 외로 이런 Profiling Tool을 과신하는 경우가 종종 있는데 그런 점은 조심해야 합니다.

좀 더 자세한 Valgrind의 정보를 얻기 원한다면 다음 Link를 방문하기 바랍니다.

2. 설치

Valgrind를 설치하는 것은 간단합니다. Terminal을 새로 열어서 다음과 같이 입력하여 설치합니다.

1
sudo apt-get install valgrind

다음 Section에서는 Test Program을 Build하면서 설명을 진행합니다. System에 Build를 위한 Package가 설치되어있지 않다면 다음과 같이 입력하여 설치합니다.

1
sudo apt-get install build-essential

3. Memory Leak 검사하기

Valgrind가 무엇인지에 대해서 알아봤고 설치도 마쳤으니, 이제 Test Program을 만들어서 Valgrind의 Memcheck 도구를 사용하여 Memory Leak을 검사하는 방법을 알아봅시다.

Gedit나 Vim과 같은 편집기를 사용해서 다음과 같은 내용을 입력한 후 test.c라고 저장합시다.

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdlib.h>

void test(void)
{
    char *= malloc(sizeof(char) * 10);
}

int main(void)
{
    test();
    return 0;
}

위의 C Code를 보면 test()에서 malloc()을 통해서 Heap Memory를 할당받았지만 사용 후에 free()를 사용하여 System에 반환하지 않았기 때문에 Memory Leak이 발생하는 것을 알 수 있습니다.

이제 이 Source를 Compile해 봅시다. Terminal에서 다음과 같이 입력하여 Debugging이 가능하도록 Option을 적용하여 Compile합니다.

1
gcc -g -o test test.c

test.c를 Compile하여 생성된 test라는 실행 File에 대해서 이제 Valgrind를 사용하여 Memory Leak을 검사해 봅시다. Terminal에서 다음과 같이 입력하여 Valgrind를 실행합니다.

1
valgrind --leak-check=yes ./test

만약 Memory Leak을 검사할 Program이 Argument(명령행 인자)를 가지고 있다면, 위의 명령에서 검사할 Program 뒤에 그대로 이어서 적으면 됩니다.

위의 명령을 실행하면 먼저 test Program이 실행되고 종료된 후에 Valgrind가 검사한 정보가 Terminal에 출력됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
==8067== Memcheck, a memory error detector
==8067== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==8067== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==8067== Command: ./test
==8067== 
==8067== 
==8067== HEAP SUMMARY:
==8067==     in use at exit: 10 bytes in 1 blocks
==8067==   total heap usage: 1 allocs, 0 frees, 10 bytes allocated
==8067== 
==8067== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==8067==    at 0x4C28FAC: malloc (vg_replace_malloc.c:236)
==8067==    by 0x400505: test (test.c:5)
==8067==    by 0x400514: main (test.c:10)
==8067== 
==8067== LEAK SUMMARY:
==8067==    definitely lost: 10 bytes in 1 blocks
==8067==    indirectly lost: 0 bytes in 0 blocks
==8067==      possibly lost: 0 bytes in 0 blocks
==8067==    still reachable: 0 bytes in 0 blocks
==8067==         suppressed: 0 bytes in 0 blocks
==8067== 
==8067== For counts of detected and suppressed errors, rerun with: -v
==8067== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)

위의 내용은 Valgrind를 실행하여 얻은 출력화면입니다. 중요한 부분은 11~14번째 Line에 있는 Memory Leak정보로, 이것은 test.c의 5번째 줄에 위치한 test()의 Code에서 Memory Leak이 발생했다는 것을 나타냅니다.

이와 같이 Memory Leak 정보에 표시된 Call Stack을 통해서 Source Code의 어느 함수의 몇번째 Line에서 Memory Leak이 발생했는지를 확인할 수 있습니다.

유의해야할 점은, Valgrind는 검사할 Program을 실행한 상태(Runtime)에서 검사하기 때문에 실행 시에 수행되지 않은 Code에 대해서는 검사할 수 없다는 것입니다. 그래서 Test Case를 잘 수행하지 않으면 Memory Leak을 검사하지 못할 수 있기 때문에 실행하기 전에 Test Case를 미리 준비하는 것이 좋습니다.

4. 마치면서…

지금까지 Valgrind를 사용하여 Memory Leak을 검사하는 방법을 간단하게 알아봤습니다. 다음 Post에서는 Valgrind의 Front-end를 사용하여 좀 더 쉽게 Memory Leak을 검사하는 방법과 Eclipse CDT로 Program을 개발했을 때 Eclipse 상에서 Valgrind를 사용하는 방법에 대해서 알아보도록 하겠습니다.


출처 : http://ioriy2k.pe.kr/archives/3754

+ Recent posts