Memory Leaks and Analysis with valgrind
Finding leaks with valgrind, interpreting reports, and common allocation pitfalls.
In C++, dynamic memory management gives the developer great flexibility, but if memory is used incorrectly, memory leak problems appear. A memory leak occurs when allocated memory is not freed, which over time causes RAM to fill up and degrades program performance. In this article, we will learn what a memory leak is, how to detect it, and how to analyze it with the Valgrind tool.
1. What Is a Memory Leak?
A memory leak is when a memory block allocated with new or malloc
is not freed with delete or free.
In this case, the memory remains occupied until the program ends and cannot be used by other processes.
#include <iostream>
using namespace std;
void createLeak() {
int *p = new int(42); // dynamic memory allocated
// delete p; // Forgot to free!
}
int main() {
createLeak();
cout << "Program ended." << endl;
}
In the example above, the memory allocated for p stays in RAM until the program finishes.
Even if the program ends, this memory is “lost” before the operating system reclaims it.
Situations like this cause serious problems especially in long-running server applications.
2. Consequences of Memory Leaks
- The application uses more and more RAM over time.
- Performance degrades and processing slows down.
- Long-running systems may eventually crash.
- On embedded systems with limited memory, the system may hang.
3. Typical Cases That Cause Leaks
- Forgetting to call delete or delete[]
- Overwriting a pointer (losing the original address)
- Returning early from a function and skipping the free
deletenot being called when an exception is thrown- Incorrect lifetime management of pointers that own dynamic objects
void badCode() {
int *p = new int[5];
p = new int[10]; // old address lost → 5 ints leaked
delete[] p;
}
4. How to Prevent Memory Leaks?
You can prevent memory leaks by following some basic principles:
- Every
newmust have a matchingdelete. - Every
new[]must have a matchingdelete[]. - After freeing a pointer, set it to
nullptr. - Apply the RAII (Resource Acquisition Is Initialization) principle.
- Use smart pointers in modern C++.
#include <iostream>
#include <memory>
using namespace std;
void safeUsage() {
auto ptr = make_unique<int>(99);
cout << *ptr << endl;
} // ptr is automatically freed when it goes out of scope
In this example, thanks to std::unique_ptr there is no need to manually call delete;
the memory is cleaned up automatically.
5. Detecting Memory Leaks (Valgrind)
Valgrind is an open source memory analysis tool that runs on Linux. It tracks all memory blocks allocated and freed during program execution and reports leaks, invalid accesses, and double frees.
Installation (Ubuntu / Debian)
sudo apt update
sudo apt install valgrind
Usage
After compiling your program, you can run it with Valgrind like this:
g++ -g program.cpp -o program
valgrind --leak-check=full ./program
The -g flag adds debugging symbols,
so line numbers will appear in the Valgrind output.
6. Sample Valgrind Output
Let’s say we have a program with a leak:
#include <iostream>
using namespace std;
int main() {
int *p = new int[3];
p[0] = 10;
p[1] = 20;
p[2] = 30;
// delete[] p; // Forgot to free!
return 0;
}
Valgrind output would look like this:
==1234== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
==1234== at 0x4C2FB55: operator new[](unsigned long) (vg_replace_malloc.c:431)
==1234== by 0x40065A: main (program.cpp:5)
==1234== LEAK SUMMARY:
==1234== definitely lost: 12 bytes in 1 blocks
This report tells us that 12 bytes (3 × int) of memory were not freed. With the line number, the problematic line can be found easily.
7. Other Useful Valgrind Options
| Option | Description |
|---|---|
--track-origins=yes | Shows where uninitialized values come from. |
--show-leak-kinds=all | Lists all kinds of leaks (definitely, indirectly). |
--num-callers=20 | Shows a deeper call stack. |
--log-file=valgrind.log | Saves the results to a file. |
8. Alternative Tools on Windows
- Visual Studio Diagnostic Tools → Provides allocation and leak analysis.
- Dr. Memory → A free Valgrind-like tool that runs on Windows.
- Deleaker → Can be used as an IDE plugin and provides detailed memory reports.
9. Best Practice Recommendations
- Write a
deletefor everynew. - Set pointers to
nullptrafter freeing them. - Make sure multiple pointers don’t point to the same address (risk of double delete).
- Use RAII to prevent resource leaks in exception scenarios.
- Use smart pointers (e.g.
std::unique_ptr) to eliminate leaks entirely.
10. TL;DR
- Memory leak = memory allocated with
newis not freed withdelete. - Valgrind is a powerful tool to detect memory leaks.
- You can test your program with
valgrind --leak-check=full ./program. - In modern C++, it’s recommended to use
std::unique_ptrorstd::shared_ptr. - On Windows, Visual Studio Diagnostic Tools or Dr. Memory can be used.
- All examples can be run with Visual Studio 2022 or GCC 11+.