[2026] Finding C++ Memory Leaks: Valgrind, AddressSanitizer, and LeakSanitizer
이 글의 핵심
Detect heap leaks with Valgrind memcheck, ASan+LSan, and Visual Studio CRT debug heap. Common leak patterns: new/delete mismatch, exceptions, shared_ptr cycles, containers of raw pointers.
Tooling: Valgrind · ownership in C++: smart pointers · Rust contrast: ownership.
Introduction: “Memory grows until OOM”
“The server runs for days, then dies”
A memory leak means you lose the last pointer to heap memory without freeing it. Long-running services eventually OOM. 아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
// 실행 예제
void handle() {
int* p = new int[1000];
// forgot delete[]
}
This article covers:
- Five major leak causes
- Valgrind (Linux)
- AddressSanitizer + LeakSanitizer
- Visual Studio / CRT helpers
- Ten leak patterns and RAII fixes
- Production monitoring ideas
Table of contents
- What is a leak?
- Five major causes
- Valgrind
- AddressSanitizer
- Visual Studio heap
- Ten patterns
- RAII
- Production monitoring
- Summary
1. What is a memory leak?
Heap memory no longer reachable from any pointer in the program → cannot be freed → grows until limits. Contrast with intentional growth (e.g. a cache) where memory is still reachable.
2. Five major causes (overview)
- new/delete mismatch or missing
delete - Exception paths skipping manual cleanup
shared_ptrcycles- Containers of raw owning pointers without cleanup
- Singletons with raw
newand no teardown
3. Valgrind
g++ -g -std=c++17 -o myapp main.cpp
valgrind --leak-check=full --show-leak-kinds=all ./myapp
Interpret definitely lost vs still reachable (globals may be “reachable” at exit).
4. AddressSanitizer / LeakSanitizer
g++ -g -fsanitize=address -std=c++17 -o myapp main.cpp
export ASAN_OPTIONS=detect_leaks=1
./myapp
Visual Studio: enable AddressSanitizer in project settings (version-dependent).
5. Visual Studio / CRT
_CrtSetDbgFlag with _CRTDBG_LEAK_CHECK_DF in debug builds for leak dumps on exit.
6. Ten patterns (titles)
- Raw
newwithoutdelete - Exception before
delete→ RAII new[]paired with wrongdeletevector<T*>without deleting elementsshared_ptrcycle → weak_ptr- Conditional
deletepaths - Rule-of-five violations (double free / leak)
- Factory returning raw owning pointer without documented ownership
- Globals with manual
new - Thread stacks leaking thread-local
new
7. RAII
Acquire in constructor / release in destructor — unique_ptr, vector, file handles, locks.
8. Production monitoring
/proc/self/status VmRSS on Linux, custom allocation counters (carefully—global operator new hooks affect everything), periodic sanity checks against baselines.
Summary
Tool comparison
| Tool | Platform | Speed | Rebuild |
|---|---|---|---|
| Valgrind | Linux | Slow | No |
| ASan/LSan | Many | ~2× | Yes |
| VS heap | Windows | Fast | Debug helpers |
Rules
- Prefer
make_unique/make_sharedover rawnew. - Containers should usually own values or smart pointers, not raw pointers.
- Break shared_ptr cycles with weak_ptr.
- Run ASan/Valgrind in CI on tests.
Related posts (internal)
Keywords
memory leak, Valgrind, AddressSanitizer, LeakSanitizer, RAII, new delete
Practical tips
- Enable ASan on developer builds by default.
- Add Valgrind stage for release candidates on Linux.
- Review any returning raw owning pointer APIs.