C언어는 개발자에게 메모리, 성능, 스택, 포인터 모든 걸 넘겨주기 때문에 버그와 성능 병목은 피할 수 없는 운명이다. 그래서 필자는 이번 글에서 디버깅 도구, 프로파일링 도구, 그리고 이 모든도구들이 어떻게 동작하고, 어떤식으로 사용해야 하는지 설명하도록 하겠다.
디버깅은 프로그램이 왜 이렇게 동작하는지 직접 메모리와 제어 흐름을 관찰하고 조작하며 답을 찾는 과정이다.
gdb는 리눅스에서 가장 널리 사용되는 C 디버깅 도구이다.
컴파일시 디버깅 정보를 포함하여야 한다.
acc -a main.c -o main
-g 옵션을 넣으면 심볼 정보와 소스코드 매핑 정보가 포함된다.
명령어 | 기능 |
---|---|
break | 중단점(breakpoint) 설정 |
run | 실행 시작 |
next | 한 줄씩 실행 |
step | 함수 내부 진입 |
변수 값 출력 | |
backtrace | 함수 호출 스택 출력 |
valgrind는 메모리 오류를 탐지한다.
valarind --leak-check=full ./main
다음과 같은 명령어를 사용하면 메모리 누수, 해제 후 사용, 초기화되지 않은 값 사용 등의 오류를 알 수 있다.
속도는 느리지만 치명적 메모리 오류는 대부분 잡아내기 때문에 사용하는것이 좋다.
ASan은 런타임에서 실시간을 오류를 탐지한다.
오버헤드는 있지만 valgrind보다 훨씬 빠르다.
버퍼 오버플로우, Use After Free, 스택/힙 경계 침범 등의 오류를 탐지하며 모던 C/C++ 에서는 필수이다.
프로파일링은 프로그램이 어디서 시간을 많이 쓰고 있는지, 어떤 함수가 병목인지를 측정하는 과정이다. 디버깅이 오류를 잡기 위한 것이였다면 프로파일링은 성능 최적화를 위한 도구이다.
gprof는 함수별 실행 시간을 분석한다.
gcc -pg main.c -o main
./main
gprof ./main gmon.out > analysis.txt
해당 명령어를 사용하면 각 함수의 호출 횟수, 소요 시간 등을 분석 가능하다. 하지만 정확한 타이밍 보장이 어렵고, 재귀 함수나 멀티스레드 환경에 약하다.
]
perf 성능 병목 탐지한다.
perf record ./main
perf report
record는 CPU 이벤트, 분기, 캐시 미스 등을 추적한다.
report는 샘플링 데이터 분석 결과이다.
perf는 아주 빠르고 시스템 전체를 분석할 수 있다.
오늘은 C언어 디버깅과 프로파일링에 대해서 알아보았다.
디버깅은 오류를 잡고, 프로파일링은 소프트웨어를 최적화 한다. 그럼 필자는 다음 글로 돌아오겠다.