반응형
Valgrind는 리눅스 실행파일(excutable)을 디버깅하고 프로파일링할 수 있는 툴입니다. 오픈소스이며 C/C++ 로 작성된 프로그램을 디버깅하는데 매우 유용하죠. 간단한 사용법과 몇 가지 기초적인 옵션에 대해 설명드리고자 합니다.
1. 설치
$ sudo apt install valgrind $ sudo apt install massif-visualizer |
2. 예제 프로그램
valgrind를 이용해 프로파일링 하기 전에 예제 프로그램을 하나 작성하였습니다. 코드는 아래와 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #include <stdio.h> #include <stdlib.h> int test1() { // 메모리 할당 및 해제 int *m; m = (int *)malloc(sizeof(int)); free(m); } int test2() { // 메모리 Leak int *m; m = (int *)malloc(sizeof(int)); } int test3() { // 메모리 Leak int *m[10]; for (int i = 0; i < 10; i++) m[i] = (int *)malloc(sizeof(int)); for (int i = 0; i < 5; i++) free(m[i]); } int test4() { // 할당되지 않은 메모리 해제 int *m; free(m); } int test5() { // Double free 문제 int *m; m = (int *)malloc(sizeof(int)); free(m); free(m); } int test6() { // 초기화 되지 않은 변수 사용 int x; if( x == 3 ) return 0; } int main(int argc, char *argv[]) { test1(); test2(); test3(); test4(); test5(); test6(); return 0; } | cs |
3. valgrind memcheck
위에서 작성한 코드를 기반으로 아래와 같이 valgrind를 이용해 프로파일링 해 보았습니다. --leak-check 옵션과 --tool , 그리고 파일로 저장하기 위한 --log-file 옵션을 사용하였습니다.
$ valgrind --leak-check=full --tool=memcheck --log-file=valgrind.log ./{example} $ cat valgrind.log ==30517== Memcheck, a memory error detector ==30517== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==30517== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==30517== Command: ./file_test ==30517== Parent PID: 30177 ==30517== ==30517== Conditional jump or move depends on uninitialised value(s) ==30517== at 0x4C2EDA1: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==30517== by 0x400A88: test4 (main.c:33) ==30517== by 0x400B2E: main (main.c:60) ==30517== ==30517== Invalid free() / delete / delete[] / realloc() ==30517== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==30517== by 0x400A88: test4 (main.c:33) ==30517== by 0x400B2E: main (main.c:60) ==30517== Address 0xbfdaca3afdd85a00 is not stack'd, malloc'd or (recently) free'd ==30517== ==30517== Invalid free() / delete / delete[] / realloc() ==30517== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==30517== by 0x400AC5: test5 (main.c:42) ==30517== by 0x400B38: main (main.c:61) ==30517== Address 0x5204840 is 0 bytes inside a block of size 4 free'd ==30517== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==30517== by 0x400AB9: test5 (main.c:41) ==30517== by 0x400B38: main (main.c:61) ==30517== Block was alloc'd at ==30517== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==30517== by 0x400AA9: test5 (main.c:40) ==30517== by 0x400B38: main (main.c:61) ==30517== ==30517== Conditional jump or move depends on uninitialised value(s) ==30517== at 0x400AE1: test6 (main.c:49) ==30517== by 0x400B42: main (main.c:62) ==30517== ==30517== ==30517== HEAP SUMMARY: ==30517== in use at exit: 24 bytes in 6 blocks ==30517== total heap usage: 14 allocs, 10 frees, 1,076 bytes allocated ==30517== ==30517== 4 bytes in 1 blocks are definitely lost in loss record 1 of 2 ==30517== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==30517== by 0x4009D8: test2 (main.c:15) ==30517== by 0x400B1A: main (main.c:58) ==30517== ==30517== 20 bytes in 5 blocks are definitely lost in loss record 2 of 2 ==30517== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==30517== by 0x400A15: test3 (main.c:24) ==30517== by 0x400B24: main (main.c:59) ==30517== ==30517== LEAK SUMMARY: ==30517== definitely lost: 24 bytes in 6 blocks ==30517== indirectly lost: 0 bytes in 0 blocks ==30517== possibly lost: 0 bytes in 0 blocks ==30517== still reachable: 0 bytes in 0 blocks ==30517== suppressed: 0 bytes in 0 blocks ==30517== ==30517== For counts of detected and suppressed errors, rerun with: -v ==30517== Use --track-origins=yes to see where uninitialised values come from ==30517== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0) | cs |
4. massif-visualizer
Text 기반으로 작성된 결과를 보는것도 좋지만 결과가 굉장히 많을 땐 정리하기 쉽지 않습니다. 이런 경우를 위해 massif-visualizer를 이용합니다. massif는 위 예제 코드를 사용하지 않고, 더 많은 memory leak을 발생시키는 예제를 사용하였습니다. --tool 옵션에 massif를 입력하고 실행합니다. 그럼 아래와 같이 massif.out.{PID} 이름으로 파일이 생성됩니다.
$ valgrind --tool=massif ./{example} ==31010== Massif, a heap profiler ==31010== Copyright (C) 2003-2015, and GNU GPL'd, by Nicholas Nethercote ==31010== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==31010== Command: ./file_test ==31010== $ ls massif.* massif.out.31010 $massif-visualizer massif.out.31010 | cs |
파일을 massif-visualizer를 이용해 오픈하면 아래와 같은 결과를 볼 수 있습니다. 좌측의 그래프는 시간에 따른 메모리 사용량 증가율이고 오른쪽은 상세 결과입니다. ^^
추가적인 옵션들은 지속적으로 정리해서 올려야 할 것 같습니다. 감사합니다.
반응형
'Linux > Debugging & Testing' 카테고리의 다른 글
[gdb] The GNU Debugger : 1. Introduction (2) | 2018.08.13 |
---|---|
[SOLVE] valgrind: failed to start tool 'memcheck' for platform... ': No such file or directory (0) | 2018.07.27 |
/Proc FileSystem - Kernel (0) | 2018.04.10 |
/Proc FileSystem - Process in More detail (2) | 2018.04.10 |
/Proc Filesystem - Process (0) | 2018.03.20 |