TraceMalloc captures stack traces of all
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-mallocfilename 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
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:
- histogram.pl, which produces a type histogram that can be diffed with histogram-diff.sh to produce output that looks like this:
---- 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.
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
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_macosx_stack.py as needed.
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.
--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
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.
Some older documentation about TraceMalloc is here.