mariadb를 python에서 테스트하기 위해서 pyodbc를 이용해서 tpcc 테스트를 진행중입니다. 그런데, mariadb odbc 드라이버에서 메모리 할당 오류가 발생합니다. 실제 다양한 프로그램을 테스트하다보면 메모리 관련 오류를 만날 수 있습니다. 이 경우에 할 수 있는 두 가지 방법을 알아보도록 하겠습니다.
Table Of Contents
1. glibc malloc_check_ 환경변수
glibc 라이브러리에서 메모리 오류를 확인하기 위해 설정할 수 있는 주요 환경 변수는 MALLOC_CHECK_입니다. 이 환경 변수는 메모리 할당 오류를 감지하고 처리하는 방법을 제어합니다.
MALLOC_CHECK_ 환경 변수의 값에 따라 다음과 같은 동작이 수행됩니다.
MALLOC_CHECK_=0: 메모리 관리 함수는 오류를 허용하고 경고를 주지 않습니다. 이 값이 기본값입니다.
MALLOC_CHECK_=1: 메모리 관리 함수는 문제가 발견되면 표준 오류에 경고 메시지를 출력합니다.
MALLOC_CHECK_=2: 메모리 관리 함수는 문제가 발견되면 abort()를 호출합니다.
MALLOC_CHECK_=3 설정은 메모리 오류가 발생하면 오류 메시지를 출력하고 abort()를 호출하면서 backtrace도 보여줍니다.
malloc_check_ 테스트 코드
아래 코드는 100바이트의 메모리를 할당하고, 할당된 메모리 범위를 넘어서 값을 쓰는 것을 시도합니다. 이는 메모리 오류를 일으키며, MALLOC_CHECK_ 환경 변수를 사용하면 이 오류를 감지할 수 있습니다.
#include <stdio.h>
#include <stdlib.h>
int main() {
char *ptr = malloc(100);
if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1;
}
/* Intentionally write beyond the allocated memory */
ptr[100] = 'a';
free(ptr);
return 0;
}
malloc_check_ 테스트 결과
위의 소스를 갖는 파일을 malloccheck.c로 저장후 다음과 같이 테스트를 해보았습니다.
MALLOC_CHECK_가 설정되어있지 않은 경우 아무 오류없이 프로그램이 정상 수행되고 종료됩니다.
하지만, MALLOC_CHECK_가 1로 설정되면 포인터 접근에대한 에러를 보여주고, 2인 경우 abort되어 core가 dump됩니다.
3인 경우에는 오류가 출력되고 backtrace와 함께 core dump가 발생합니다.
% gcc -o mcheck malloccheck.c
% ./mcheck
% env |grep MALLOC
% export MALLOC_CHECK_=1
% ./mcheck
*** Error in `./mcheck': free(): invalid pointer: 0x0000000002079010 ***
% export MALLOC_CHECK_=2
% ./mcheck
중지됨 (core dumped)
% export MALLOC_CHECK_=3
% ./mcheck
*** Error in `./mcheck': free(): invalid pointer: 0x000000000180d010 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7f566)[0x7f8496d06566]
./mcheck[0x4005d7]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f8496ca8c05]
./mcheck[0x4004f9]
======= Memory map: ========
00400000-00401000 r-xp 00000000 103:01 4380423494 /lswhh/tmp/mcheck
00600000-00601000 r--p 00000000 103:01 4380423494 /lswhh/tmp/mcheck
00601000-00602000 rw-p 00001000 103:01 4380423494 /lswhh/tmp/mcheck
0180d000-0182e000 rw-p 00000000 00:00 0 [heap]
7f8496a71000-7f8496a86000 r-xp 00000000 fd:00 206522296 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f8496a86000-7f8496c85000 ---p 00015000 fd:00 206522296 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f8496c85000-7f8496c86000 r--p 00014000 fd:00 206522296 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f8496c86000-7f8496c87000 rw-p 00015000 fd:00 206522296 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f8496c87000-7f8496e3f000 r-xp 00000000 fd:00 201347848 /usr/lib64/libc-2.17.so
7f8496e3f000-7f849703f000 ---p 001b8000 fd:00 201347848 /usr/lib64/libc-2.17.so
7f849703f000-7f8497043000 r--p 001b8000 fd:00 201347848 /usr/lib64/libc-2.17.so
7f8497043000-7f8497045000 rw-p 001bc000 fd:00 201347848 /usr/lib64/libc-2.17.so
7f8497045000-7f849704a000 rw-p 00000000 00:00 0
7f849704a000-7f849706b000 r-xp 00000000 fd:00 206927864 /usr/lib64/ld-2.17.so
7f849724a000-7f849724d000 rw-p 00000000 00:00 0
7f8497269000-7f849726b000 rw-p 00000000 00:00 0
7f849726b000-7f849726c000 r--p 00021000 fd:00 206927864 /usr/lib64/ld-2.17.so
7f849726c000-7f849726d000 rw-p 00022000 fd:00 206927864 /usr/lib64/ld-2.17.so
7f849726d000-7f849726e000 rw-p 00000000 00:00 0
7ffcdf04a000-7ffcdf06c000 rw-p 00000000 00:00 0 [stack]
7ffcdf11a000-7ffcdf11c000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
중지됨 (core dumped)
glibc는 glibc.malloc.check, glibc.malloc.top_pad, glibc.malloc.perturb, glibc.malloc.mmap_threshold 등의 메모리 할당 튜닝 가능 변수를 제공합니다.
2. valgrind
Valgrind는 메모리 디버깅, 메모리 누수 탐지, 프로파일링 등을 수행할 수 있는 프로그래밍 도구입니다. Valgrind를 사용하면 메모리 누수를 쉽게 찾아낼 수 있습니다.
Valgrind를 사용하여 메모리 누수를 찾는 방법은 다음과 같습니다:
Valgrind 설치
- Valgrind는 리눅스에서 기본적으로 제공되지만, 설치되어 있지 않은 경우에는 패키지 관리자를 통해 설치할 수 있습니다. 예를 들어, Ubuntu에서는 다음 명령을 사용하여 Valgrind를 설치할 수 있습니다.
sudo apt-get -y install valgrind
#아래와 같이 실행하면 설치가 완료됩니다.
lswhh@lswhh-KVM:~$ sudo apt-get -y install valgrind
[sudo] password for lswhh:
패키지 목록을 읽는 중입니다... 완료
의존성 트리를 만드는 중입니다... 완료
상태 정보를 읽는 중입니다... 완료
다음의 추가 패키지가 설치될 것입니다 :
libc6-i386
제안하는 패키지:
valgrind-dbg valgrind-mpi kcachegrind alleyoop valkyrie
다음 새 패키지를 설치할 것입니다:
libc6-i386 valgrind
0개 업그레이드, 2개 새로 설치, 0개 제거 및 91개 업그레이드 안 함.
16.9 M바이트 아카이브를 받아야 합니다.
이 작업 후 91.8 M바이트의 디스크 공간을 더 사용하게 됩니다.
받기:1 http://kr.archive.ubuntu.com/ubuntu jammy-updates/main amd64 libc6-i386 amd64 2.35-0ubuntu3.6 [2,837 kB]
받기:2 http://kr.archive.ubuntu.com/ubuntu jammy/main amd64 valgrind amd64 1:3.18.1-1ubuntu2 [14.1 MB]
내려받기 16.9 M바이트, 소요시간 7초 (2,373 k바이트/초)
Selecting previously unselected package libc6-i386.
(데이터베이스 읽는중 ...현재 237780개의 파일과 디렉터리가 설치되어 있습니다.)
Preparing to unpack .../libc6-i386_2.35-0ubuntu3.6_amd64.deb ...
Unpacking libc6-i386 (2.35-0ubuntu3.6) ...
설치된 패키지 libc6:i386 (2.35-0ubuntu3.6)의 파일로 대체됩니다...
Selecting previously unselected package valgrind.
Preparing to unpack .../valgrind_1%3a3.18.1-1ubuntu2_amd64.deb ...
Unpacking valgrind (1:3.18.1-1ubuntu2) ...
libc6-i386 (2.35-0ubuntu3.6) 설정하는 중입니다 ...
valgrind (1:3.18.1-1ubuntu2) 설정하는 중입니다 ...
Processing triggers for man-db (2.10.2-1) ...
Processing triggers for libc-bin (2.35-0ubuntu3.6) ...
lswhh@lswhh-KVM:~$ which valgrind
/usr/bin/valgrind
예제코드
- 아래 예제 코드는 100 byte를 할당 후 해제하지 않아 leak이 발생하는 코드입니다.
% cat valcheck.c
#include <stdio.h>
#include <stdlib.h>
int main() {
char *ptr = malloc(100);
if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1;
}
/*ptr is leak*/
return 0;
}
프로그램 컴파일
- Valgrind는 디버깅 정보가 없어도 사용할 수 있습니다. 하지만, 프로그램을 -g 옵션으로 컴파일하여 디버깅 정보를 포함하면 더 많은 정보를 출력해 줍니다. 예를 들어, gcc -g -o vcheck valcheck.c 명령을 사용하여 프로그램을 컴파일할 수 있습니다.
Valgrind 실행
- Valgrind를 실행하여 메모리 누수를 찾습니다. 다음과 같은 명령을 사용하여 Valgrind를 실행할 수 있습니다:
valgrind --leak-check=full --error-limit=no ./vcheck
이 명령은 my_program을 실행하고 메모리 누수를 찾습니다 --leak-check=full 옵션은 모든 개별 누수를 보여주고, --error-limit=no 옵션은 모든 오류를 보여줍니다.
결과 분석
- Valgrind는 메모리 누수와 관련된 정보를 출력합니다. 이 정보를 분석하여 메모리 누수를 찾을 수 있습니다.
- 아래의 결과를 보면 "definitely lost: 100 bytes in 1 blocks" 100byte 블록 1개가 누수된 것을 확인할 수 있습니다.
% gcc -o vcheck valcheck.c
lswhh: ~/tmp
% valgrind --leak-check=full --error-limit=no ./vcheck
==122798== Memcheck, a memory error detector
==122798== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==122798== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==122798== Command: ./vcheck
==122798==
==122798==
==122798== HEAP SUMMARY:
==122798== in use at exit: 100 bytes in 1 blocks
==122798== total heap usage: 1 allocs, 0 frees, 100 bytes allocated
==122798==
==122798== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==122798== at 0x4C2B067: malloc (vg_replace_malloc.c:380)
==122798== by 0x400553: main (in /lswhh/tmp/vcheck)
==122798==
==122798== LEAK SUMMARY:
==122798== definitely lost: 100 bytes in 1 blocks
==122798== indirectly lost: 0 bytes in 0 blocks
==122798== possibly lost: 0 bytes in 0 blocks
==122798== still reachable: 0 bytes in 0 blocks
==122798== suppressed: 0 bytes in 0 blocks
==122798==
==122798== For lists of detected and suppressed errors, rerun with: -s
==122798== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Valgrind는 프로그램의 메모리 오류를 찾는데 사용되는 매우 훌융한 도구이며, 메모리 누수 외에도 다양한 종류의 프로그램 오류를 찾는 데 사용할 수 있습니다.
'IT' 카테고리의 다른 글
Ubuntu Linux에서 MariaDB ODBC 드라이버 업데이트 하기 - CentOS, RockyOS, RHEL, Debian (21) | 2024.03.11 |
---|---|
우분투에서 Mariadb ODBC 드라이버 메모리 오류 분석하기 (0) | 2024.03.05 |
디자인 전공자를 위한 가격을 고려한 프리미엄 노트북 추천 (0) | 2024.03.01 |
영상편집 가능한 사무용 가성비 노트북 추천 (21) | 2024.03.01 |
2024년 가성비 좋은 노트북 추천 BEST 4 - 대학생, 사무용, 캐주얼 게임 (22) | 2024.02.29 |