Memory Leaks & Debugging in C
A memory leak happens when a program allocates memory using
malloc(), calloc(), or realloc()
but fails to release it using free().
Over time, this causes the program to consume more RAM, slow down, or even crash.
What is a Memory Leak?
A memory leak occurs when:
- Memory is allocated dynamically
- Pointer to allocated memory is lost
- Program has no way to free the memory
- Eventually, RAM usage increases abnormally
Memory leaks are common in long-running applications like servers, devices, sensors, and OS software.
Causes of Memory Leaks
- Forgetting to free memory
- Overwriting the pointer holding allocated memory
- Losing reference after returning from a function
- Multiple malloc() without free()
- Incorrect pointer handling
Example 1 – Memory Leak (Bad Code)
#include <stdio.h>
#include <stdlib.h>
int main() {
int *p = malloc(5 * sizeof(int));
p = NULL; // original address lost — memory leak
return 0;
}
Here, memory was allocated but the pointer was overwritten.
The program can no longer free that memory → memory leak.
Example 2 – Proper Memory Management
#include <stdio.h>
#include <stdlib.h>
int main() {
int *p = malloc(5 * sizeof(int));
// Use memory
for(int i=0;i<5;i++) p[i] = i;
free(p); // Memory released safely
return 0;
}
Debugging Memory Leaks
Tools that help detect leaks:
- Valgrind (Linux)
- AddressSanitizer (ASan)
- GCC Sanitizers
- Debugger Logs (printf, logs)
- Static Analysis Tools (gcc -Wall, clang)
Using Valgrind (Leak Checker)
valgrind --leak-check=full ./a.out
It reports:
- Memory still reachable
- Definitely lost
- Probably lost
- Errors from invalid free / double free
Definitely lost → real memory leak
Indirectly lost → related to leaked parent blocks
Still reachable → program ended before freeing (not harmful)
Common Memory Leak Patterns
- malloc but no free
- Returning pointer to local variable
- Assigning new malloc() to an existing pointer
- Losing pointer in function call
- Not checking NULL after malloc
Example 3 – Double Allocation (Leak)
#include <stdio.h>
#include <stdlib.h>
int main() {
int *p = malloc(10);
p = malloc(20); // 1st allocation leaked
free(p);
return 0;
}
Example 4 – Returning Dynamic Memory (Correct)
#include <stdio.h>
#include <stdlib.h>
int* getArray() {
int *p = malloc(5 * sizeof(int));
return p; // safe — caller must free()
}
int main() {
int *arr = getArray();
free(arr);
return 0;
}
Best Practices to Avoid Memory Leaks
- Always free allocated memory
- Set pointer to NULL after free
- Keep track of all malloc() calls
- Use tools like Valgrind and ASan
- Avoid unnecessary malloc()
💡 Rule of Thumb:
Every malloc(), calloc() or realloc() must have a matching free().
Practice Questions
- What is a memory leak? Explain with example.
- How does overwriting a pointer cause memory leak?
- What does Valgrind detect?
- Why should we set pointer to NULL after free?
- Explain different types of memory errors in Valgrind report.
Practice Task
Write a program that dynamically allocates an array, fills values, prints them, and frees memory.
Use pointer debugging logs to track memory usage.