debugging · medium

Debugging: Valgrind — Memcheck, Callgrind, Massif, Helgrind

Valgrind is a virtual machine that instruments all memory accesses without recompilation. Memcheck (default): intercepts every load/store; reports invalid reads/writes (OOB, UAF), uninitialized reads (--track-origins=yes), double-frees, and memory leaks. Leak categories: definitely lost (fix!) > indirectly lost > possibly lost/still reachable (usually benign). Callgrind: counts instructions per function; use kcachegrind for call graph GUI. Massif: heap snapshot timeline; ms_print ASCII chart; massif-visualizer GUI; find memory growth spikes. Helgrind: detects lock order violations before deadlock; reports even if the deadlock didn't trigger this run. DRD: alternative race detector with lower false-positive rate. Comparison with ASAN: Valgrind is 10-30x slower but needs no recompile; ASAN is 2x slower but needs -fsanitize=address.

🔑 Key line

Valgrind Memcheck: no recompile; 10-30x slow; catches UAF/OOB/leaks; definitely lost = real leaks; Callgrind = CPU instruction count profiler; Massif = heap usage over time; Helgrind = lock order violation detector.

The code

# Valgrind Memcheck — memory error + leak detector
valgrind --leak-check=full --show-leak-kinds=all \
--track-origins=yes --error-exitcode=1 ./app
# 10-30x slower; no recompile needed; detects all ASAN categories
# track-origins=yes: shows where uninitialized values came from
# Callgrind — instruction profiler (for CPU hotspots)
valgrind --tool=callgrind --callgrind-out-file=cg.out ./app
callgrind_annotate cg.out | head -60 # text summary
kcachegrind cg.out # GUI flame-graph view
# Massif — heap profiler (memory usage over time)
valgrind --tool=massif --pages-as-heap=yes ./app
ms_print massif.out.PID | head -80 # ASCII chart
massif-visualizer massif.out.PID # GUI timeline
# Helgrind — thread error detector
valgrind --tool=helgrind ./app
# Detects: data races, lock-order violations, improper unlock
# Alternative to TSAN when you can't recompile with -fsanitize
# DRD — another race detector with lower false-positive rate
valgrind --tool=drd ./app
# Typical Memcheck output format:
# ==PID== Invalid read of size 4
# ==PID== at 0x... MyClass::use (myclass.cpp:47)
# ==PID== by 0x... main (main.cpp:12)
# ==PID== Address 0x... is 0 bytes after a block of size 40 alloc'd
# ==PID== at 0x... operator new (myclass.cpp:10)

What this lesson walks through

  1. 01Valgrind overview — the Swiss Army knife of memory analysis
  2. 02Memcheck — heap out-of-bounds access
  3. 03Memcheck leak report — definitely vs possibly lost
  4. 04Callgrind — CPU profiler: find the hottest functions
  5. 05Massif — heap profiler: track memory growth over time
  6. 06Helgrind — lock order violation detector

Valgrind is a virtual machine that runs your program under instrumented x86 emulation. Memcheck (default) intercepts every memory operation. No recompile needed — unlike ASAN. 10-30x slower but catches everything ASAN does and more. Multiple tools: Callgrind (CPU profile), Massif (heap profile), Helgrind (race detection), DRD (data race).

See it animated — step by step, at your own pace

Unlock the full interactive walkthrough of Debugging: Valgrind — Memcheck, Callgrind, Massif, Helgrind and 100+ animated C++ interview lessons.

← Previous
Debugging: ASAN/TSAN/LSAN/UBSan — Runtime Memory and Race Detection
Next →
Debugging: perf + Flame Graph — CPU Profiling, Hotspots, and Bound Type Diagnosis