Hunting Memory Leaks: Glibc Malloc Tuning
Writing a C daemon that runs for months is a test of character. One small malloc() without a free() and you'll find your process killed by the OOM (Out Of Memory) killer just when traffic peaks. Glibc's allocator is efficient, but it can be opaque. Here's how to peek under the hood and tune it for long-term stability.
The Magic of MALLOC_CHECK_
If you suspect heap corruption (the dreaded "double free" or "buffer overflow"), don't reach for a heavy debugger yet. Use the environment variable MALLOC_CHECK_.
# Set MALLOC_CHECK_ to 2 to abort immediately on error
export MALLOC_CHECK_=2
./my_daemon
When set to 2, glibc uses a slightly slower but more robust allocation algorithm that adds "guards" around your memory blocks. If you corrupt them, the program crashes immediately with a backtrace. It's the fastest way to find that one stray strcpy.
Tuning with mallopt()
Glibc doesn't always return memory to the system immediately. It keeps a "pool" to speed up future allocations. For a daemon, this can look like a leak. You can tune this behavior with mallopt().
#include <malloc.h>
// Disable the "fastbins" to reduce fragmentation
mallopt(M_MXFAST, 0);
// Set the threshold for when to use mmap() instead of sbrk()
// Large allocations are better handled by mmap as they return to OS immediately
mallopt(M_MMAP_THRESHOLD, 128 * 1024);
Inspecting with malloc_stats()
If you want to know what's happening in real-time, call malloc_stats() and pipe it to a log file. It will show you exactly how many bytes are in use, how many are in "free chunks," and how much has been mmap'ed.
malloc_stats();
Remember: free() is just a suggestion to glibc. If you really want to ensure memory is released to the OS, you need to understand the relationship between sbrk and mmap.