Loading...

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


3. Typical Cases That Cause Leaks


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:


#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

OptionDescription
--track-origins=yesShows where uninitialized values come from.
--show-leak-kinds=allLists all kinds of leaks (definitely, indirectly).
--num-callers=20Shows a deeper call stack.
--log-file=valgrind.logSaves the results to a file.

8. Alternative Tools on Windows


9. Best Practice Recommendations


10. TL;DR

  • Memory leak = memory allocated with new is not freed with delete.
  • 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_ptr or std::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+.

Related Articles