Memory leaks are among the most frustrating bugs to track down in C and C++ applications. They silently consume resources, degrade performance, and can eventually cause your application to crash.
Fortunately, Valgrind offers a powerful suite of tools to help identify and fix these elusive issues. In this guide, we’ll explore how to effectively use Valgrind to detect and resolve memory leaks in your applications.
Valgrind is an instrumentation framework used to build dynamic analysis tools that detect memory management and threading bugs. Its most popular tool, Memcheck,
Originally developed for Linux, Valgrind now supports multiple platforms including macOS and FreeBSD.
Read: How to fix high memory usage in Ubuntu
Before detecting memory leaks, ensure Valgrind is installed on your system:
# For Debian-based systems (Ubuntu)
sudo apt install valgrind
# For Red Hat-based systems (CentOS, Fedora)
sudo yum install valgrind
# For Arch-based systems
sudo pacman -Syu valgrind
# For FreeBSD
sudo pkg ins valgrind
The simplest way to use Valgrind is by running your executable through it:
valgrind ./your_program arg1 arg2 This command runs your program with Memcheck enabled and reports any issues found.
For thorough memory leak detection, use:
valgrind --leak-check=full
--show-leak-kinds=all
--track-origins=yes
--verbose
--log-file=valgrind-out.txt
./your_program arg1 arg2
This command provides detailed leak reports, tracks the origins of uninitialized values, and logs the output for review.
Read: Monitor and Optimize Memory Usage on Ubuntu 22.04 for Peak Performance
After analysis, Valgrind outputs a detailed report. For example:
HEAP SUMMARY:
in use at exit: 0 bytes in 0 blocks
total heap usage: 636 allocs, 636 frees, 25,393 bytes allocated
All heap blocks were freed -- no leaks are possible
ERROR SUMMARY: 0 errors from 0 contexts
This indicates that all allocated memory was properly freed. If leaks are detected, Valgrind will list details for each lost memory block.
To get detailed, line-by-line information about memory issues, compile your program with debug flags:
# Standard compilation
gcc -o executable -std=c11 -Wall main.c
# With debug information
gcc -o executable -std=c11 -Wall -ggdb3 main.c
This enables Valgrind to report the exact source file and line number where the leak occurred. For optimizations that preserve debuggability, use -Og instead.
Example:
#include
int main() {
char* string = malloc(5 * sizeof(char)); // LEAK: not freed!
return 0;
}
Solution: Always free dynamically allocated memory when done.
#include
int main() {
char* string = malloc(5 * sizeof(char));
// Use string...
free(string); // Memory freed
return 0;
}
Example:
#include
#include
struct _List {
int32_t* data;
int32_t length;
};
typedef struct _List List;
List* resizeArray(List* array) {
int32_t* dPtr = array->data;
dPtr = realloc(dPtr, 15 * sizeof(int32_t)); // Leak: original pointer not updated
return array;
}
int main() {
List* array = calloc(1, sizeof(List));
array->data = calloc(10, sizeof(int32_t));
array = resizeArray(array);
free(array->data);
free(array);
return 0;
}
Solution: Update the original pointer when using realloc:
List* resizeArray(List* array) {
array->data = realloc(array->data, 15 * sizeof(int32_t)); // Fixed
return array;
}
Example:
#include
#include
int main() {
char* alphabet = calloc(26, sizeof(char));
for(uint8_t i = 0; i Open source has come a long way. Recently I was watching a keynote address by…
Sylva 1.5 becomes the first release to include Kubernetes 1.32, bringing the latest open source…
Expansion ensures business continuity without forcing major upgrades Today, Canonical announced the expansion of the…
TL;DR: YARD-Lint catches documentation issues, just like RuboCop for code. Star it and use it…
Deploy a FedRAMP-ready kubernetes cluster and application suite, with FIPS 140-3 crypto and DISA-STIG hardening…
This new release brings the stability and security of Ubuntu to Axion-based N4A virtual machines…