Leak Detection

메모리 누수 탐지

누수는 delete를 잊은 줄 하나만의 문제가 아니다. 예외 경로, 순환 참조, 캐시 정책, C API 경계에서 소유권이 사라질 때 생긴다.

01

도구로 재현한다

LeakSanitizer나 Valgrind로 누수 stack trace를 얻고 입력을 고정한다.

02

소유권 경로를 따라간다

할당된 객체가 어느 컨테이너, 포인터, callback에 넘어갔는지 마지막 참조를 찾는다.

03

타입으로 막는다

raw new/delete를 unique_ptr, vector, string, RAII wrapper로 바꿔 반복 누수를 차단한다.

definitely lost
해제 경로 없음 마지막 포인터를 잃어 프로그램이 더 이상 해제할 수 없다.
가장 먼저 고친다.
indirectly lost
잃은 객체가 잡은 객체 루트 객체가 누수되며 그 안의 메모리도 함께 누수된다.
근본 원인을 먼저 찾는다.
still reachable
종료 시 남은 메모리 전역 캐시나 싱글턴처럼 포인터는 남아 있지만 해제하지 않은 상태다.
정책상 허용 여부를 정한다.
shared cycle
카운트 기반 누수 A와 B가 shared_ptr로 서로 소유하면 둘 다 파괴되지 않는다.
한 방향을 weak_ptr로 바꾼다.

new/delete · C API · 순환 점검

new/delete 직접 new가 보이면 예외 경로에서도 delete가 보장되는지보다 RAII 대체를 먼저 본다.
C API malloc, fopen, custom handle을 받는 경계에 전용 deleter가 있는가.
순환 shared_ptr 그래프에 부모-자식 또는 양방향 참조가 남아 있지 않은가.

전용 deleter

using FilePtr = std::unique_ptr<FILE, decltype(&std::fclose)>;

FilePtr file(std::fopen(path.c_str(), "rb"), &std::fclose);
if (!file) throw std::runtime_error("open failed");