[c] 메모리 누수(memory leak)/다른 에러들 점검 방법
c로 코딩을 할 때는 아주 골치 아픈 일 중 한가지가 memory leak, 즉 메모리 누수를 잡는 것이라고 생각한다.
사실 간단한 코딩을 할 때는 누수를 잡지 않아도 코드 실행 상에는 아무런 문제가 없다.
그렇지만 메모리 할당 해제를 해주지 않는다면 어디선가 자원 낭비가 되고 있다는 것이기에 메모리 누수를 잡아주어야 한다.
메모리 누수를 탐지하는 것은 1번보다 2번에서 잘 나오긴 한다.
그래서 메모리 누수를 보고싶을 때는 2번을 사용하고 어디선가 segment fault가 나오거나 다른 에러들이 나올 때 1번을 사용해서 찾으면 좋다.
memory leak을 잡을 때 아주 유용하게 사용하는 방법이 두 가지 있다.
1. 컴파일 할 때 플래그 넣어주기
보통 gcc로 컴파일을 할텐데 그 때 -fsanitize=address 플래그를 넣어주면 된다.
gcc -g3 -fsanitize=address get_next_line.c && ./a.out
이렇게 하면 메모리 누수가 어디서 났는지도 볼 수 있고, free가 중복해서 됐다거나, free하고 사용했다거나 segment fault가 어디서 났는지 등 자세하게 볼 수 있다.
위에 사진을 보면 우리는 뒤에 무슨 에러가 났는지 알려주는 ERROR 줄과 그 아래 파랑, 초록, 분홍 글씨만 보면 된다.
일단 heap-use-after-free, 즉 동적할당한 무언가가 free 이후에 사용되었다는 에러다.
일단 파란 글씨 아래를 보면 어디서 문제가 발생하는지 알 수 있다. 0 1 2 3의 순서로 적혀있지만 3 2 1 0 순이 코드 진행 순서이다.
그래서 3에서 start를 했고 2에서 get_next_line_man.c의 154번째 줄의 main에서 함수로 들어가서 최종적으로 get_next_line_man.c의 39번째 줄 read_line함수 안에서 문제가 발생했다.
그 다음 초록 글씨 아래 freed by thread T0 here 은 그러면 어디서 free를 해줬어? 라는 의미고
그 아래 문단 previously allocated by thread T0 here 은 이전에 어디서 할당을 해줬어? 라는 의미이다.
2. main문에 메모리 누수 검사해주는 문장 추가하기
system("leaks --list -- a.out");
main 끝에 이 문장을 추가해주면 leak이 있는지 검사해준다.
gcc *.c 를 해준 후 a.out을 실행시키면 아래처럼 나온다.
하지만 이 문장만 넣는다면 위처럼 어디서 메모리 누수가 나는지 알 수 없기에
export MallocStackLogging=1
터미널에서 이 문장을 입력하고 컴파일 하고 실행해주면 좋다.
문장들이 주르륵 나오는데 다 볼 필요는 없고 우리가 볼 것은 leaks가 들어간 문장만 보면 된다.
아까보다 조금 더 자세해졌다.
하지만 나는 정확히 몇 번째 줄에서 malloc한게 메모리 누수가 나는지 알고 싶다.
그럴 때는 gcc에 -g 플래그를 주면 된다!
-g1, -g2, -g3이 있는데 -g를 하면 기본적으로 g3이 적용된다고 한다.
그러면 이렇게 어느 함수에서 몇번째 줄에서 malloc이 실행됐고, 그게 누수가 난다~를 볼 수 있다.
처음부터 읽어보면 get_next_line_man.c의 main에서 시작되고, 함수들을 타고타고 들어간다.
그래서 malloc은 get_next_line_utils_man.c의 57번째 줄 ft_substr 함수에서 실행이 됐고, 그 때 동적할당한 메모리 때문에 누수가 난다는 것이다.
참고자료
https://80000coding.oopy.io/457f637f-b101-4f79-adc8-0ca72bd3c6f3