TraceMalloc

TraceMalloc has been superseded by DMD and removed from the codebase. This documentation is only relevant to older versions of the codebase that still contain it.

TraceMalloc captures stack traces of all malloc, calloc , realloc, and free calls (this currently covers all operator new and delete calls in Mozilla, too). To enable TraceMalloc in your build, configure with --enable-trace-malloc. The built Mozilla application will support the following additional command-line options:

  • --trace-malloc filename The application will log allocation and deallocation events with stack traces in a binary format to the given file. If filename is -, nothing is written to a file, but TraceMalloc will be active and will track live allocations and their stack traces.
  • --shutdown-leaks=filename On shutdown, the application will save live allocations (with stack traces) to the given file.

Analyzing the trace-malloc log

Tools such as bloatblame (tools/trace-malloc/bloatblame.cpp) can be used to process filename. Try running with the unified output format option, -u. The output is a large HTML file that hyperlinks ancestor and descendent libraries, classes, and functions that call into one another, attributing malloc blame up and down each graph. Bloatblame accumulates allocation counts and ignores free calls.

If you run with --trace-malloc -, your code can call NS_TraceMallocDumpAllocations(pathname) at opportune times, and a human-readable listing of the current heap, including stack traces for every allocation, will be written to pathname. This file can be post-processed by tools in mozilla/tools/trace-malloc as follows:

---- Base ----   ---- Incr ----   ----- Difference ----
Type                    Count    Bytes   Count    Bytes   Count    Bytes %Total
TOTAL                   48942  4754774   76136  6566453   27194  1811679 100.00
nsTokenAllocator           17   110007      60   388260      43   278253  15.36
nsImageGTK                476  2197708     341  2366564    -135   168856   9.32
nsMemCacheRecord          843    45767    2328   124767    1485    79000   4.36
nsTextNode                209    11704    1614    90384    1405    78680   4.34
HTMLAttributesImpl        482    14288    2824    88400    2342    74112   4.09
nsScanner                  58    76824      94   146300      36    69476   3.83
nsScriptError             253    25070     842    91548     589    66478   3.67
nsHTMLDocument.mReferrer    177    21550     691    85460     514    63910   3.53
nsHTMLValue               139     7846    1215    68734    1076    60888   3.36
HTMLContentSink             6     4816      12    57782       6    52966   2.92
  • uncategorized.pl, which lists all the void* allocations (the ones that couldn't be categorized by type), sorted by size.

Also, your JavaScript can call the following DOM window methods:

  • TraceMallocDisable() - turn off tracing, first flushing any buffered log events for all log files.
  • TraceMallocEnable() - turn on tracing.
  • TraceMallocOpenLogFile(filename) - open a new log file and return its log file descriptor (or -1 on error).
  • TraceMallocChangeLogFD(logfd) - change the current log file to the one identified by logfd, returning the previous fd (so you can maintain a number of open files; keep their fds in a JS Array!).
  • TraceMallocCloseLogFD(logfd) - close the log file identified by logfd, flushing its buffer of any events first. If logfd identifies the current log file, change the current log file to the default log file given by the --trace-malloc command line argument.
  • TraceMallocLogTimestamp(caption) - log a timestamp event to the current log file, annotating the log even with the caption string.
  • TraceMallocDumpAllocations(pathname) - dump a human-readable listing of all traced, live allocations.

See nsTraceMalloc.h for detailed comments on the log file format.

Analyzing the shutdown log

The shutdown log is a basic tool for finding memory leaks. The shutdown log contains the stack trace of every allocation that has not been deallocated by shutdown. Some of these are false positives, allocations that are truly needed until shutdown. Ideally, these would be freed explicitly, to make it easier to find real leaks using the shutdown log. Here is a how-to for analyzing the shutdown log, taken from the Tinderbox leak builds. This example is for MacOS; small modifications are needed for other platforms.

# Run application with shutdown logging
# Note: Tinderbox leak tests use: python leaktest.py -- --trace-malloc malloc.log --shutdown-leaks=sdleak.log
# Note 2: It appears that the shutdown log is not recorded if --trace-malloc is given the - argument.
build/dist/Minefield.App/Contents/MacOS/firefox --trace-malloc /dev/null --shutdown-leaks=sdleak.log
# Convert raw log to text representation of call trees
perl source/tools/trace-malloc/diffbloatdump.pl --depth=15 --use-address /dev/null sdleak.log > sdleak.tree.raw
# Frobulate trees to remove extraneous junk
perl source/tools/rb/fix-macosx-stack.pl sdleak.tree.raw > sdleak.tree

You can also use the leakstats program to analyze a log for shutdown leaks. It will produce a report like the following.

Leaks: 382739 bytes, 3465 allocations
Maximum Heap Size: 7751799 bytes
62095212 bytes were allocated in 391091 allocations.

Detecting memory usage growth in a running process

To do this, dump the existing allocations to a file by calling the function TraceMallocDumpAllocations from JavaScript. You can use the following web page to do so.

<script type="text/javascript">
    var filename = window.prompt("Filename to log: ");
    if (filename)
      TraceMallocDumpAllocations(filename);
</script>

One can then use the script tools/trace-malloc/diffbloatdump.pl to compare trace-malloc dumps before and after doing an action that might leak. If there are significant differences, it might be worth examining the call stacks for the destructors of the objects in question to see what is extending their lifetime. (This can be done by examining the unprocessed output of an XPCOM_MEM_REFCNT_LOG, one of the nsTraceRefcnt logs.) You should use the --use-address argument to diffbloatdump.pl, and then the diff tree can be run through fix_linux_stack.py or fix_macosx_stack.py as needed.

Leaksoup

Leaksoup is a trace-malloc tool that analyzes the shutdown log. Because this log includes the contents of heap blocks, leaksoup can analyze the graph of live objects and determine which allocations are roots (within that graph, of course -- stack allocations and global variables don't count). Leaksoup also finds sets of objects that are rooted by a cycle (i.e., a set of reference counted objects that own references to each other in a cycle). However, it cannot distinguish between owning and non-owning pointers, which means that non-owning pointers that are nulled out by destructors may show up in leaksoup as cycles. However, despite that, it is probably the easiest way to determine what leak roots are present.

Run using both the --trace-malloc and --shutdown-leaks options. Ignore the allocations log, and run leaksoup over the memory dump (which is a dump of all allocations still live at shutdown) with a command such as ./run-mozilla.sh ./leaksoup sdleak.log > sdleak.html. This generates a large HTML file as output.

The output of leaksoup begins with all the leak roots, and then lists all the non-root allocations. The roots are either listed as single objects or as strongly connected components (minimal sets of nodes in the graph in which any node is reachable from all other nodes). (A strongly connected component with only one node is listed as a single object.) Any single object listed as a root is really a leak root, and any component listed as a root either (a) contains an object that is a root or (b) contains objects that form an ownership cycle that is a root.

Other documentation

Some older documentation about TraceMalloc is here.