Memory Analysis: Valgrind, heaptrack, memray, Heap Profiling


Introduction





Memory issues — leaks, fragmentation, excessive allocation, and buffer overflows — are among the hardest bugs to diagnose. Specialized memory analysis tools can pinpoint the exact line of code causing the problem. This article covers Valgrind for C/C++ memory errors, heaptrack for Linux heap profiling, memray for Python memory tracking, and general heap profiling techniques.





Valgrind





The gold standard for C/C++ memory error detection:






# Basic memory check


valgrind ./myapp


valgrind --leak-check=yes ./myapp


valgrind --tool=memcheck --leak-check=full ./myapp




# Detailed output


valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./myapp




# Suppress known leaks


valgrind --suppressions=suppressions.txt ./myapp




# Generate suppression file


valgrind --leak-check=full --gen-suppressions=all ./myapp 2> suppressions.txt




# Cache profiling


valgrind --tool=cachegrind ./myapp




# Call graph profiling


valgrind --tool=callgrind ./myapp




# Massif (heap profiler)


valgrind --tool=massif ./myapp


ms_print massif.out.12345 # View heap profile




# Profile specific duration


valgrind --tool=callgrind --dump-instr=yes --simulate-cache=yes ./myapp








// Example of errors Valgrind catches


void memory_errors() {


// Buffer overflow — Valgrind catches this


char buf[10];


buf[10] = 'x'; // Error: invalid write




// Use-after-free


char *ptr = malloc(10);


free(ptr);


ptr[0] = 'a'; // Error: invalid read/write




// Memory leak


char *leak = malloc(100); // Never freed


// Valgrind: definitely lost: 100 bytes




// Uninitialized value


int x;


if (x == 5) {} // Error: conditional depends on uninit value


}







**Key tools**: `memcheck` for memory errors and leaks, `cachegrind` for cache profiling, `callgrind` for call graph analysis, `massif` for heap profiling.





heaptrack





A modern Linux heap memory profiler with lower overhead than Valgrind:






# Installation


sudo apt install heaptrack # Debian/Ubuntu


brew install heaptrack # macOS (partial)




# Profile an application


heaptrack ./myapp


heaptrack ./myapp arg1 arg2




# Attach to running process


heaptrack -p 12345




# Analyze results


heaptrack_print heaptrack.myapp.12345.gz


heaptrack_gui heaptrack.myapp.12345.gz # GUI viewer




# Output analysis


heaptrack_print --print-leak-types --print-total heaptrack.myapp.12345.gz







**Key features**: Lower overhead than Valgrind (suitable for production-like loads), call-stack-based allocation tracking, detailed time-based allocation charts, peak memory analysis, leak detection.





memray





Python memory profiler with high-resolution tracking:






# Installation


pip install memray




# Profile a script


memray run myapp.py


memray run -o output.bin myapp.py




# Profile with live tracking


memray run --live myapp.py




# Attach to running process


memray attach --pid 12345 --output output.bin




# Generate reports


memray flamegraph output.bin # Interactive flamegraph


memray table output.bin # Text table report


memray tree output.bin # Tree view


memray stats output.bin # Summary statistics


memray summary output.bin # High-level summary




# Compare allocations


memray diff before.bin after.bin




# Python native support








# Programmatic memory tracking


import memray




with memray.Tracker("profile.bin"):


# Code to profile


data = [i for i in range(1000000)]


processed = [x * 2 for x in data]




# Decorator for function profiling


@memray.tracker("func_profile.bin")


def my_function():


pass




# Context manager with specific recording


with memray.Tracker("allocations.bin", native_traces=True):


large_list = [object() for _ in range(500000)]







**Key features**: Python-native (no C extension needed in many cases), thread-safe, native stack traces, live tracking, multiple report formats including interactive flamegraphs.





General Heap Profiling





jemalloc heap profiling






# Enable jemalloc profiling


export MALLOC_CONF="prof:true,prof_active:true,lg_prof_sample:17"


./myapp




# Trigger profile dump


kill -SIGUSR2 $PID # Dumps heap profile


jeprof --show_bytes --pdf ./myapp heap.prof > heap.pdf




# Compare profiles


jeprof --show_bytes --pdf ./myapp --base=heap1.prof heap2.prof > diff.pdf







GCC address sanitizer






# Compile with address sanitizer


gcc -fsanitize=address -g -O1 myapp.c -o myapp


./myapp # Will detect buffer overflows and use-after-free




# Leak sanitizer


gcc -fsanitize=leak -g myapp.c -o myapp







Memory Analysis Workflow






# 1. Detect the issue (OOM or high RSS growth)


# 2. Run with memcheck for memory errors


valgrind --leak-check=full ./myapp




# 3. Profile heap with massif or heaptrack


heaptrack ./myapp




# 4. Analyze the profile


heaptrack_print heaptrack.*.gz




# 5. For Python: use memray


memray run myapp.py


memray flamegraph memray-myapp.*.bin







Comparison





| Tool | Language | Overhead | Best For |


|------|----------|----------|----------|


| Valgrind | C/C++ | 10-20x | Memory errors, leaks |


| heaptrack | C/C++/Rust | 2-3x | Heap allocation profiling |


| memray | Python | 1.5-3x | Python memory tracking |


| jemalloc | C/C++ | Low | Production heap profiling |


| ASan | C/C++ | 2x | Buffer overflows, UAF |





Recommendations




* **C/C++ memory errors**: Valgrind memcheck is the definitive tool for finding use-after-free, buffer overflows, and uninitialized values.

* **C/C++ heap profiling**: heaptrack for lower overhead than Valgrind, suitable for larger applications.

* **Python memory analysis**: memray for high-resolution tracking and flamegraph visualization.

* **Production C/C++**: jemalloc profiling for continuous heap monitoring with minimal overhead.

* **Quick memory error detection**: GCC/Clang address sanitizer during development.




Start with the lowest-overhead tool for your language. For C/C++, use ASan during development and heaptrack for deeper analysis. For Python, memray is the best all-around choice. Reserve Valgrind for hard-to-find memory errors that simpler tools miss.