Identifying memory leaks

A memory leak occurs when memory is allocated but not freed when it is no longer needed. Memory leakage is by no means unique to embedded systems, but it becomes an issue partly because targets don't have much memory in the first place, and partly because they often run for long periods of time without rebooting, allowing the leaks to become a large puddle.

You will realize that there is a leak when you run free or top and see that free memory is continually going down, even if you drop caches, as shown in the preceding section. You will be able to identify the culprit (or culprits) by looking at the Uss and Rss per process.

There are several tools for identifying memory leaks in a program. I will look at two: mtrace and Valgrind.

mtrace is a component of glibc that traces calls to malloc(3), free(3), and related functions, and identifies areas of memory not freed when the program exits. You need to call the mtrace() function from within the program to begin tracing and then at runtime, write a path name to the MALLOC_TRACE environment variable in which the trace information is written. If MALLOC_TRACE does not exist or of the file cannot be opened, mtrace hooks are not not installed. While the trace information is written in ASCII, it is usual to use the mtrace command to view it.

Here is an example:

Here is what you might see when running the program and looking at the trace:

Unfortunately, mtrace does not tell you about leaked memory while the program runs. It has to terminate first.

Valgrind is a very powerful tool for discovering memory problems including leaks, and other things besides. One advantage is that you don't have to recompile the programs and libraries that you want to check, although it does work better if they have been compiled with the -g option so that they include debug symbol tables. It works by running the program in an emulated environment and trapping execution at various points. This leads to the big downside of Valgrind, which is that the program runs at a fraction of normal speed which makes it less useful for testing anything with real-time constraints.

Valgrind contains several diagnostic tools:

You can select the tool you want with the -tool option. Valgrind runs on the major embedded platforms: ARM (Cortex A), PPC, MIPS, and x86 in 32- and 64-bit variants. It is available as a package in both the Yocto Project and Buildroot.

To find our memory leak, we need to use the default memcheck tool, with the option --leakcheck=full to print out the lines where the leak was found: