Your program was cruising… then boom. 2 a.m. reboot.
Been there? I have.
Last winter I shipped a tiny backend service—300 lines, clean code, all unit tests green. Two days later the pager screams. RAM climbs like a rocket and the box grinds to a halt. Not fun.
The culprit? A single strdup
with no matching free
. Classic.
The real fix was rookie-easy once I stopped *guessing* and let the right tool show me the exact line.
Here’s how I do it now—step-by-step—so you can skip the wild goose chase.
Skip the printf whack-a-mole
Dumping a bunch of printf("got here\n")
into a multi-threaded C++ beast is like hunting a gas leak with a match. It can work… or you level the house.
What you need instead:
- Proof that a leak exists and how big it is.
- The **exact stack trace** leading to that allocation.
- Visual proof you can show your team (and yourself) on Monday morning.
Pick the right tool for the job
1. Valgrind — the forensic lab
Valgrind is the gold-standard. It’s thorough, but heavy: think 10×–20× slowdown. Perfect for off-hours or unit-test runs.
Install (30 seconds):
sudo apt-get install valgrind
Run a leak check:
valgrind --leak-check=full ./my_app
You’ll end up with a plain-text report. If you see:
==12345== 400 bytes in 1 blocks are definitely lost
==12345== at 0x483DD99: calloc
==12345== by 0x109234: make_buffer (buffer.c:12)
…you know line 12 in buffer.c stole 400 bytes and never gave them back.
2. Heaptrack — the drone with night vision
Valgrind might be science-grade, but Heaptrack is fast. Only ~2Ă— slowdown. I pop it onto long-running services without killing them.
Install (30 seconds):
sudo apt-get install heaptrack heaptrack-gui
Launch:
heaptrack ./my_server
Move the resulting .heaptrack
file to any laptop (even if your server is headless), then:
heaptrack --analyze my_server.heaptrack
A colorful flame graph pops up. Click the tallest spike, read the backtrace, spot the loop stuffing stuff into std::vector
every five seconds. Done.
A practical game plan you can do today
I run this script on every feature branch:
- Compile debug symbols:
-g -O0
. - Quick smoke-test:
heaptrack ./app --quick-check
. Takes one minute. - If I see a steady RAM climb, I circle back:
- Deep dive:
valgrind --leak-check=full ./app
(maybe grab coffee). - Fix. Usually a missing
free
or a C++std::unique_ptr
capture issue. - Re-run. Commit. Sleep easy.
Quick FAQs I hear in Slack
Can I use these on Rust or Go?
Valgrind works, but Rust’s borrow checker already guards you. For Go, use go tool trace
instead.
My server has no GUI, can I still use Heaptrack?
Yes. Capture on the server, analyze on your laptop.
Valgrind is killing my game loop!
Pick Heaptrack first. Use Valgrind only when you’ve narrowed the suspect code.
Final thought
Memory leaks won’t steal your reputation—**inaction will**. Run one of these tools right now on your current branch. Ten minutes upfront can save you a red-eye call from ops.
You’re not “bad at memory”. You just haven’t given yourself the right microscope yet.