Debugging memory leaks

  • Revision slug: Debugging/Debugging_memory_leaks
  • Revision title: Debugging memory leaks
  • Revision id: 46703
  • Created:
  • Creator: Sheppy
  • Is current revision? No
  • Comment caps

Revision Content

The Mozilla team has developed a number of memory analysis tools to augment commercial tools like Purify. These can help us more quickly spot and fix memory leaks and memory bloat (our term for taking up too much memory, aka footprint). Here's a list of what we have at our disposal:

  • BloatView - This tool dumps out per-class statistics on the total number of refcounts and instances, as well as unreleased refcounts and un-deleted instances, and the amount of memory consumed by them. (more below)
  • Boehm GC Leak Detector - The Boehm garbage collector has be modified to serve as a leak detector. It's output can be post-processed by the "Leak Soup" tool to find the roots of leaked objects. This lets developers quickly focus on the key objects that need to be freed, rather than the whole graph of objects to which they refer. (more below)
  • Refcount Tracing - Stack traces can also be dumped out for object allocations and refcounting. This information can be post-processed by the Refcount Balancer tool to match up AddRefs and Releases to find the code that has missing Releases. (more below)
  • Trace Malloc - A tree of callsites, where paths from the root to leaves form stack traces that call malloc, calloc, realloc, and free, can by built in-process by building with --enable-trace-malloc and running with --trace-malloc filename. As malloc, free, etc. are called, log events identifying the function call and its callsite are emitted to filename. (more below).
  • Leaky - This tool also dumps out stack traces (in a slightly different format) and can again be used to match up AddRefs with Releases in order to find missing Release calls. (more below)
  • Menu items to interactively control Purify - Interactively triggering a dump of all leaks or new leaks from within the running application is still one of the best ways to debug leaks in your subsystem. Menu items for this can be enabled for both viewer and apprunner. (more [{{mediawiki.external('#Purify|below')}}\)

More description on each of these will be provided below.

Also see a newer overview of what leak tools we have.

How to turn on refcnt/memory logging

Assuming you have a build with refcnt logging enabled (we'll tell you how to do that next), here's what you have to do to use it. All of the following environment variables can be set to any of these values:

  • 1 - log to stdout
  • 2 - log to stderr
  • filename - write log to a file

The log environment variables are:

XPCOM_MEM_BLOAT_LOG
If this environment variable is set then xpcom will use the "bloat" trackers. The bloat trackers gather data for the BloatView output that occurs when the program exits, when about:bloat is loaded, or a call to nsTraceRefcnt::DumpStatistics is made.
When an addref/release/ctor/dtor call is made, the data is logged and attributed to the particular data type.
By default enabling this environment variable will cause the BloatView software to dump out the entire database of collected data. If all you want to see is that data for objects that leaked, set the environment variable XPCOM_MEM_LEAK_LOG.
XPCOM_MEM_LEAK_LOG
This is basically a subset of XPCOM_MEM_BLOAT_LOG, and only shows classes that had object that were leaked, instead of statistics for all classes.
XPCOM_MEM_REFCNT_LOG
Setting this environment variable enables refcount tracing.
Only enable this for severe pain (unless you are using refcount tracing or leaky, see below). What this does is to enable logging (to stdout) of each and every call to addref/release without discrimination to the types involved. The output includes mapping the call-stacks at the time of the call to symbolic forms (on platforms that support this) and thus will be *very* *VERY* *VERY* slow. Did I say slow? It is not as slow when using XPCOM_MEM_LOG_CLASSES and XPCOM_MEM_LOG_OBJECTS
XPCOM_MEM_COMPTR_LOG
This environment variable enables logging of additions and releases of objects into nsCOMPtrs. This is currently only enabled on Linux.
XPCOM_MEM_ALLOC_LOG
For losing architectures (those that don't have stack-crawl software written for them), xpcom supports logging at the *call site* to AddRef/Release using the usual cpp __FILE__ and __LINE__ number macro expansion hackery. This results in slower code, but at least you get *some* data about where the leaks might be occurring from.
XPCOM_MEM_LEAKY_LOG
For platforms that support leaky, xpcom will endeavor to find at run time the symbols __log_addref and __log_release and if found, instead of doing the slow painful stack crawls at program execution time instead it will pass the buck to the leaky software. This will allow your program to actually run in user friendly real time, but does require that your platform support leaky. Currently only linux supports leaky.

In addition, the following variable may be set to a list of class names:

XPCOM_MEM_LOG_CLASSES
Instead of slowing to a useless halt, instead you can slow to a mere crawl by using this option. When enabled, the xpcom logging software will look for the XPCOM_MEM_LOG_CLASSES environment variable (for platforms that support getenv). The variable contains a comma separated list of names which will be used to compare against the type's of the objects being logged. For example:
 env XPCOM_MEM_LOG_CLASSES=nsWebShell XPCOM_MEM_REFCNT_LOG=1 ./apprunner
will show you just the AddRef/Release calls to instances of nsWebShell while running apprunner. Note that setting XPCOM_MEM_LOG_CLASSES will also list the serial number of each object that leaked in the "bloat log" (that is, the file specified by the XPCOM_MEM_BLOAT_LOG variable). An object's serial number is simply a unique number, starting at one, that is assigned to the object when it is allocated.

You may use an object's serial number with the following variable to further restrict the reference count tracing:

XPCOM_MEM_LOG_OBJECTS
Set this variable to a comma-separated list of object serial number or ranges of serial number, e.g., 1,37-42,73,165. When this is set, along with XPCOM_MEM_LOG_CLASSES and XPCOM_MEM_REFCNT_LOG, a stack track will be generated for only the specific objects that you list. For example,
 env XPCOM_MEM_LOG_CLASSES=nsWebShell XPCOM_MEM_LOG_OBJECTS=2 XPCOM_MEM_REFCNT_LOG=1 ./apprunner
will dump stack traces to the console for the 2nd nsWebShell object that gets allocated, and nothing else.


BloatView

BloatView dumps out per-class statistics on allocations and refcounts, and provides gross numbers on the amount of memory being leaked broken down by class. Here's a sample of the BloatView output:

   BloatView: ALL (cumulative) LEAK AND BLOAT STATISTICS
    |<------Class----->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|
                         Per-Inst   Leaked    Total      Rem      Mean       StdDev     Total      Rem      Mean       StdDev
  0 TOTAL                     193  2480436   316271    12852 ( 5377.07  /-  5376.38)   410590    16079 ( 2850.93  /-  2849.79)
  1 StyleSetImpl               32        0        8        0 (    3.88  /-     3.15)     6304        0 (    7.18  /-     6.63)
  2 SinkContext                32        0       19        0 (    1.87  /-     1.04)        0        0 (    0.00  /-     0.00)
  3 nsXPCClasses               12        0        2        0 (    1.00  /-     0.71)       41        0 (    5.57  /-     4.98)
  4 NameSpaceURIKey             8       72      158        9 (    8.16  /-     7.62)        0        0 (    0.00  /-     0.00)
  5 nsSupportsArray            36    11304     2581      314 (  477.13  /-   476.53)     9223      314 (  579.23  /-   578.64)
  6 nsView                     96        0       57        0 (   27.64  /-    26.98)        0        0 (    0.00  /-     0.00)
  7 nsEnderDocumentObser       12        0        1        0 (    0.50  /-     0.87)        1        0 (    0.50  /-     0.87)

Here's how you interpret the columns:

  • Class - The name of the class in question. (Warning: The class name is truncated to 20 characters.)
  • Bytes Per-Inst - The number of bytes returned if you were to write sizeof(Class). Note that this number does not reflect any memory held onto by the class, such as internal buffers, etc. (E.g. for nsStr -- you're seeing the size of the header struct, not the size of the string!)
  • Bytes Leaked - The number of bytes per instance times the number of objects leaked (Bytes Per-Inst * Objects Rem). Use this number to look for the worst offenders. (Should be zero!)
  • Objects Total - The total count of objects allocated of a given class.
  • Objects Rem - The number of objects allocated of a given class that weren't deleted. (Should be zero!)
  • Objects Mean - The mean (average) number of objects of a given class across the lifetime of the run. Data points are taken whenever new and delete are called (not at regular intervals).
  • Objects StdDev - The standard deviation in the mean number of objects allocated.
  • References Total - The total number of AddRefs performed on a given class.
  • References Rem - The number of references on a given class that weren't Released. (Should be zero!)
  • References Mean - The mean (average) number of references to a given class across the lifetime of the run. Data points are taken whenever AddRef and Release are called (not at regular intervals).
  • References StdDev - The standard deviation in the mean number of references

Interesting things to look for:

  • Are your classes in the list? - Look! If they aren't, then you're not using the NS_IMPL_ADDREF and NS_IMPL_RELEASE (or NS_IMPL_ISUPPORTS which calls them) for xpcom objects, or MOZ_COUNT_CTOR and MOZ_COUNT_DTOR for non-xpcom objects. Not having your classes in the list is not ok. That means no one is looking at them, and we won't be able to tell if someone introduces a leak. (see {{mediawiki.external('#Instrumenting below')}} for how to fix this)
  • The Bytes Leaked for your classes should be zero! - Need I say more? If it isn't, you should use the other tools to fix it.
  • The number of objects remaining might be equal to the total number of objects. This could indicate a hand-written Release method (that doesn't use the NS_LOG_RELEASE macro from nsTraceRefcnt.h), or perhaps you're just not freeing any of the instances you've allocated. These sorts of leaks are easy to fix.
  • The total number of objects might be 1. This might indicate a global variable or service. Usually this will have a large number of refcounts.
  • The number of refcounts might equal the total number of objects. This class might be a candidate for a non-xpcom object (but be very cautious about changing this if it implements any interfaces besides nsISupports).
  • The mean number of objects is much lower than the total. This indicates a few objects of this class are allocated and then freed, as opposed to the opposite case where there's a big build-up of instances that are all freed together (perhaps at the end of the program).

You can also dump out bloat statistics interactively by typing about:bloat in the location bar, or by using the menu items under the QA menu in debug builds. Note that you need to have the XPCOM_MEM_BLOAT_LOG or XPCOM_MEM_LEAK_LOG envirionment variable defined first. You can also type about:bloat?new to get a log since the last time you called it, or about:bloat?clear to clear the current set of statistics completely (use this option with caution as it can result in what look like negative refcounts, etc). Whenever these options are used, the log data is dumped to a file relative to the program's directory:

 bloatlogs/all-1999-10-16-010302.txt (a complete log resulting from the about:bloat command)
 bloatlogs/new-1999-10-16-010423.txt (an incremental log resulting from the about:bloat?new command)

Viewing, Sorting, and Comparing Bloat Logs

You can view one or more bloat logs in your browser by running the following program:

perl mozilla/tools/memory/bloattable.pl log1 log2 ... logn > htmlfile

This will produce an HTML file that contains a table such as:

Byte Bloats

Name File Date
blank <tt>blank.txt</tt> Tue Aug 29 14:17:40 2000
mozilla <tt>mozilla.txt</tt> Tue Aug 29 14:18:42 2000
yahoo <tt>yahoo.txt</tt> Tue Aug 29 14:19:32 2000
netscape <tt>netscape.txt</tt> Tue Aug 29 14:20:14 2000

The numbers do not include malloc 'd data such as string contents.

Click on a column heading to sort by that column. Click on a class name to see details for that class.

{{mediawiki.external('javascript:reloadSelf(0,0) Class Name')}}

{{mediawiki.external('javascript:reloadSelf(1,0) Instance<br/> Size')}}

Bytes allocated Bytes allocated but not freed

blank

mozilla

yahoo

netscape

Total

blank

mozilla

yahoo

netscape

Total

TOTAL







1754408 432556 179828 404184 2770976

nsStr

20 6261600 3781900 1120920 1791340 12955760 222760 48760 13280 76160 360960

nsHashKey

8 610568 1842400 2457872 1134592 6045432 32000 536 568 1216 34320

nsTextTransformer

548 8220 469088 1414936 1532756 3425000 0 0 0 0 0

nsStyleContextData

736 259808 325312 489440 338560 1413120 141312 220800 -11040 94944 446016

nsLineLayout

1100 2200 225500 402600 562100 1192400 0 0 0 0 0

nsLocalFile

424 558832 19928 1696 1272 581728 72080 1272 424 -424 73352

The first set of columns, Bytes allocated, shows the amount of memory allocated for the first log file (<tt>blank.txt</tt>), the difference between the first log file and the second (<tt>mozilla.txt</tt>), the difference between the second log file and the third (<tt>yahoo.txt</tt>), the difference between the third log file and the fourth (<tt>netscape.txt</tt>), and the total amount of memory allocated in the fourth log file. These columns provide an idea of how hard the memory allocator has to work, but they do not indicate the size of the working set.

The second set of columns, Bytes allocated but not freed, shows the net memory gain or loss by subtracting the amount of memory freed from the amount allocated.

The Show Objects and Show References buttons show the same statistics but counting objects or AddRef'd references rather than bytes.

Comparing Bloat Logs

You can also compare any two bloat logs (either those produced when the program shuts down, or written to the bloatlogs directory) by running the following program:

perl mozilla/tools/tinderbox/bloatdiff.pl <previous-log> <current-log>

This will give you output of the form:

 Bloat/Leak Delta Report
 Current file:  dist/win32_D.OBJ/bin/bloatlogs/all-1999-10-22-133450.txt
 Previous file: dist/win32_D.OBJ/bin/bloatlogs/all-1999-10-16-010302.txt
 --------------------------------------------------------------------------
 CLASS                     LEAKS       delta      BLOAT       delta
 --------------------------------------------------------------------------
 TOTAL                   6113530       2.79%   67064808       9.18%
 StyleContextImpl         265440      81.19%     283584     -26.99%
 CToken                   236500      17.32%     306676      20.64%
 nsStr                    217760      14.94%    5817060       7.63%
 nsXULAttribute           113048     -70.92%     113568     -71.16%
 LiteralImpl               53280      26.62%      75840      19.40%
 nsXULElement              51648       0.00%      51648       0.00%
 nsProfile                 51224       0.00%      51224       0.00%
 nsFrame                   47568     -26.15%      48096     -50.49%
 CSSDeclarationImpl        42984       0.67%      43488       0.67%

This "delta report" shows the leak offenders, sorted from most leaks to fewest. The delta numbers show the percentage change between runs for the amount of leaks and amount of bloat (negative numbers are better!). The bloat number is a metric determined by multiplying the total number of objects allocated of a given class by the class size. Note that although this isn't necessarily the amount of memory consumed at any given time, it does give an indication of how much memory we're consuming. The more memory in general, the worse the performance and footprint. The percentage 99999.99% will show up indicating an "infinite" amount of leakage. This happens when something that didn't leak before is now leaking.

Bloat Statistics on Tinderbox

Each build rectangle on Tinderbox will soon be capable of displaying the total leaks delta and bloat delta percentages from one build to the next. Horray!

warren L C
L:-3
B: 21

Hmmm. Warren checked in and the number of leaks went down by 3%. (Yes!) But the amount of bloat went up by 21%. (Ouch!) This probably should be investigated further. Sometimes bloat can go up because new features were added that just take up more memory (or if the set of test URLs were changed, and the activity is different from last time), but in general we'd like to see both of these numbers continue to go down. You can look at the end of the log (by clicking on the L) to see the bloat statistics and delta report for a breakdown of what actually happened.

Boehm GC Leak Detector

more...


Refcount Tracing

Refcount tracing is used to capture stack traces of AddRef and Release calls to use with the Refcount Balancer. It is best to set the XPCOM_MEM_REFCNT_LOG environment variable to point to a file when using it.

See Refcount Balancer for more information. Also see the tutorial on finding leaks of XPCOM objects.


Trace Malloc

TraceMalloc captures stack traces of all <tt>malloc</tt>, <tt>calloc</tt> , <tt>realloc</tt>, and <tt>free</tt> calls (this currently covers all <tt>operator new</tt> and <tt>delete</tt> calls in Mozilla, too). To enable TraceMalloc in your build, configure with --enable-trace-malloc. Run the resulting mozilla with --trace-malloc filename as an argument, and a binary log of events and callsite relations will be written to filename . If filename is -, nothing is written, but the TraceMalloc machinery keeps track of all live allocations, and builds its tree of callsites to keep book on stack backtraces.

Tools such as bloatblame (<tt>tools/trace-malloc/bloatblame.c</tt>) 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:

  • <tt>TraceMallocDisable()</tt> - turn off tracing, first flushing any buffered log events for all log files.
  • <tt>TraceMallocEnable()</tt> - turn on tracing.
  • <tt>TraceMallocOpenLogFile(filename)</tt> - open a new log file and return its log file descriptor (or -1 on error).
  • <tt>TraceMallocChangeLogFD(logfd)</tt> - 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!).wa
  • <tt>TraceMallocCloseLogFD(logfd)</tt> - 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.
  • <tt>TraceMallocLogTimestamp(caption)</tt> - log a timestamp event to the current log file, annotating the log even with the caption string.
  • <tt>TraceMallocDumpAllocations(pathname)</tt> - dump a human-readable listing of all traced, live allocations.

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

Leaky

Using this stuff with leaky

First, setup these environment variables:

 setenv LD_PRELOAD ../lib/libleaky.so   #assumes you execute apprunner/viewer in the dist/bin directory
 setenv LIBMALLOC_LOG 8                 #tells leaky to log addref/release calls
 setenv XPCOM_MEM_LEAKY_LOG 1           #use leaky
 setenv XPCOM_MEM_LOG_CLASSES "a,b,c"   #the list of types you care about

Then run the viewer or the apprunner and run your test. Then exit it. The result will be some large file in your current directory called <tt>malloc-log</tt> and a small file called <tt>malloc-map</tt>. If these aren't there then something's wrong.

If it works properly, then you now have the tracing data for the problem you are chasing in malloc-log. Use leaky to convert it to human readable form and debug away:

leaky -dRq <viewer|apprunner> malloc-log > /tmp/log

Leaky used to require c filt, but now it does it itself. With the -R option, leaky will only log the refcnts that actually leaked (those that didn't go to zero).

Leaky environment variables

LD_PRELOAD
Set this to the pathname to libleaky.so if you are using leaky to track memory operations.
LIBMALLOC_LOG
Set this to "8" to enable leaky to track addref/release calls that are logged by xpcom. Note that you must set bit 8 in xpcomrefcnt to connect xpcom's tracing to leakys tracing.

Sample output

Here is what you see when you enable some logging with XPCOM_MEM_LOG_CLASSES set to something:


 nsWebShell      0x81189f8       Release 5
 nsWebShell::Release(void) 0x59
 nsCOMPtr<nsIContentViewerContainer>::~nsCOMPtr(void) 0x34
 nsChannelListener::OnStartRequest(nsIChannel *, nsISupports *) 0x550
 nsFileChannel::OnStartRequest(nsIChannel *, nsISupports *) 0x7b
 nsOnStartRequestEvent::HandleEvent(void) 0x46
 nsStreamListenerEvent::HandlePLEvent(PLEvent *) 0x62
 PL_HandleEvent 0x57
 PL_ProcessPendingEvents 0x90
 nsEventQueueImpl::ProcessPendingEvents(void) 0x1d
 nsAppShell::SetDispatchListener(nsDispatchListener *) 0x3e
 gdk_get_show_events 0xbb
 g_io_add_watch 0xaa
 g_get_current_time 0x136
 g_get_current_time 0x6f1
 g_main_run 0x81
 gtk_main 0xb9
 nsAppShell::Run(void) 0x245
 nsAppShell::Run(void) 0xc7a92ede
 nsAppShell::Run(void) 0xc7a9317c
 __libc_start_main 0xeb

Here is what you see when you use the leaky tool to dump out addref/release leaks:

addref 082cccc8 0 00000001 --> CViewSourceHTML::AddRef(void) CViewSourceHTML::QueryInterface(nsID &, void **) NS_NewViewSourceHTML(nsIDTD **) .LM708 GetSharedObjects(void) nsParser::RegisterDTD(nsIDTD *) RDFXMLDataSourceImpl::Refresh(int) nsChromeRegistry::InitRegistry(void) nsChromeProtocolHandler::NewChannel(char *, nsIURI *, nsILoadGroup *, nsIEventSinkGetter *, nsIChannel **) nsIOService::NewChannelFromURI(char *, nsIURI *, nsILoadGroup *, nsIEventSinkGetter *, nsIChannel **) NS_OpenURI(nsIChannel **, nsIURI *, nsILoadGroup *, nsIEventSinkGetter *) NS_OpenURI(nsIInputStream **, nsIURI *) CSSLoaderImpl::LoadSheet(URLKey &, SheetLoadData *) CSSLoaderImpl::LoadChildSheet(nsICSSStyleSheet *, nsIURI *, nsString &, int, int) CSSParserImpl::ProcessImport(int &, nsString &, nsString &) CSSParserImpl::ParseImportRule(int &) CSSParserImpl::ParseAtRule(int &) CSSParserImpl::Parse(nsIUnicharInputStream *, nsIURI *, nsICSSStyleSheet *&) CSSLoaderImpl::ParseSheet(nsIUnicharInputStream *, SheetLoadData *, int &, nsICSSStyleSheet *&) CSSLoaderImpl::LoadAgentSheet(nsIURI *, nsICSSStyleSheet *&, int &, void (*)(nsICSSStyleSheet *, void *), void *) nsLayoutModule::Initialize(void) nsLayoutModule::GetClassObject(nsIComponentManager *, nsID &, nsID &, void **) nsNativeComponentLoader::GetFactoryFromModule(nsDll *, nsID &, nsIFactory **) nsNativeComponentLoader::GetFactory(nsID &, char *, char *, nsIFactory **) .LM1381 nsComponentManagerImpl::FindFactory(nsID &, nsIFactory **) nsComponentManagerImpl::CreateInstance(nsID &, nsISupports *, nsID &, void **) nsComponentManager::CreateInstance(nsID &, nsISupports *, nsID &, void **) RDFXMLDataSourceImpl::Refresh(int) nsChromeRegistry::InitRegistry(void) nsChromeProtocolHandler::NewChannel(char *, nsIURI *, nsILoadGroup *, nsIEventSinkGetter *, nsIChannel **) nsIOService::NewChannelFromURI(char *, nsIURI *, nsILoadGroup *, nsIEventSinkGetter *, nsIChannel **) NS_OpenURI(nsIChannel **, nsIURI *, nsILoadGroup *, nsIEventSinkGetter *) nsDocumentBindInfo::Bind(nsIURI *, nsILoadGroup *, nsIInputStream *, unsigned short *) nsDocLoaderImpl::LoadDocument(nsIURI *, char *, nsIContentViewerContainer *, nsIInputStream *, nsISupports *, unsigned int, unsigned int, unsigned short *) nsWebShell::DoLoadURL(nsIURI *, char *, nsIInputStream *, unsigned int, unsigned int, unsigned short *) nsWebShell::LoadURI(nsIURI *, char *, nsIInputStream *, int, unsigned int, unsigned int, nsISupports *, unsigned short *) nsWebShell::LoadURL(unsigned short *, char *, nsIInputStream *, int, unsigned int, unsigned int, nsISupports *, unsigned short *) nsWebShell::LoadURL(unsigned short *, nsIInputStream *, int, unsigned int, unsigned int, nsISupports *, unsigned short *) nsWebShellWindow::Initialize(nsIWebShellWindow *, nsIAppShell *, nsIURI *, int, int, nsIXULWindowCallbacks *, int, int, nsWidgetInitData &) nsAppShellService::JustCreateTopWindow(nsIWebShellWindow *, nsIURI *, int, int, unsigned int, nsIXULWindowCallbacks *, int, int, nsIWebShellWindow **) nsAppShellService::CreateTopLevelWindow(nsIWebShellWindow *, nsIURI *, int, int, unsigned int, nsIXULWindowCallbacks *, int, int, nsIWebShellWindow **) OpenChromURL(char *, int, int) HandleBrowserStartup(nsICmdLineService *, nsIPref *, int) DoCommandLines(nsICmdLineService *, int) main1(int, char **) main __libc_start_main


Purify

more...

How to build xpcom with refcnt/memory logging

Built into xpcom is the ability to support the debugging of memory leaks. By default, an optimized build of xpcom has this disabled. Also by default, the debug builds have the logging facilities enabled. You can control either of these options by changing environment variables before you build mozilla:

FORCE_BUILD_REFCNT_LOGGING
If this is defined then regardless of the type of build, refcnt logging (and related memory debugging) will be enabled in the build.
NO_BUILD_REFCNT_LOGGING
If this is defined then regardless of the type of build or of the setting of the FORCE_BUILD_REFCNT_LOGGING, no refcnt logging will be enabled and no memory debugging will be enabled. This variable overrides FORCE_BUILD_REFCNT_LOGGING.

The remaining discussion assumes that one way or another that xpcom has been built with refcnt/memory logging enabled.

How to instrument your objects for refcnt/memory logging

First, if your object is an xpcom object and you use the NS_IMPL_ADDREF and NS_IMPL_RELEASE (or a variation thereof) macro to implement your AddRef and Release methods, then there is nothing you need do. By default, those macros support refcnt logging directly.

If your object is not an xpcom object then some manual editing is in order. The following sample code shows what must be done:

 MyType::MyType()
 {
     MOZ_COUNT_CTOR(MyType);
 }
 MyType::~MyType()
 {
     MOZ_COUNT_DTOR(MyType);
 }


What are those macros doing for me anyway?

NS_IMPL_ADDREF has this additional line in it:

 NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this));

What this is doing is logging the AddRef call using XPCOM's nsTraceRefcnt class. The implementation of that macro is:

 #define NS_LOG_ADDREF(_p, _rc, _type, _size) \
     nsTraceRefcnt::LogAddRef((_p), (_rc), (_type), (PRUint32) (_size))

Which as you can see just passes the buck to nsTraceRefcnt. nsTraceRefcnt implements the logging support and will track addref/release/ctor/dtor calls in a database that it builds up as the program is executing. In a similar manner, NS_IMPL_RELEASE uses NS_LOG_RELEASE which uses nsTraceRefcnt::LogRelease.

For the MOZ_COUNT_CTOR and MOZ_COUNT_DTOR macros the expansion boils down to calls to nsTraceRefcnt::LogCtor and nsTraceRefcnt::LogDtor calls. Again, the type of the object is passed in as well as the sizeof of all the data type.

 #define MOZ_COUNT_CTOR(_type) \
     PR_BEGIN_MACRO \
         nsTraceRefcnt::LogCtor((void*)this, #_type, sizeof(*this)); \
     PR_END_MACRO
 #define MOZ_COUNT_DTOR(_type) \
     PR_BEGIN_MACRO \
         nsTraceRefcnt::LogDtor((void*)this, #_type, sizeof(*this));
     PR_END_MACRO

Original Document Information

  • Author(s): unknown
  • Last Updated Date: August 17, 2006
  • Copyright Information: Portions of this content are © 1998–2007 by individual mozilla.org contributors; content available under a Creative Commons license.

Revision Source

<p>The Mozilla team has developed a number of memory analysis tools to augment commercial tools like Purify. These can help us more quickly spot and fix memory leaks and memory bloat (our term for taking up too much memory, aka footprint). Here's a list of what we have at our disposal:
</p>
<ul><li> <b>BloatView</b> - This tool dumps out per-class statistics on the total number of refcounts and instances, as well as unreleased refcounts and un-deleted instances, and the amount of memory consumed by them. (more <a href="#BloatView">below</a>)
</li><li> <b>Boehm GC Leak Detector</b> - The Boehm garbage collector has be modified to serve as a leak detector. It's output can be post-processed by the "Leak Soup" tool to find the roots of leaked objects. This lets developers quickly focus on the key objects that need to be freed, rather than the whole graph of objects to which they refer. (more <a href="#Boehm_GC_Leak_Detector">below</a>)
</li><li> <b>Refcount Tracing</b> - Stack traces can also be dumped out for object allocations and refcounting. This information can be post-processed by the <a class="external" href="http://www.mozilla.org/performance/refcnt-balancer.html">Refcount Balancer</a> tool to match up AddRefs and Releases to find the code that has missing Releases. (more <a href="#Refcount_Tracing">below</a>)
</li><li> <b>Trace Malloc</b> - A tree of callsites, where paths from the root to leaves form stack traces that call malloc, calloc, realloc, and free, can by built in-process by building with --enable-trace-malloc and running with --trace-malloc <i>filename</i>. As malloc, free, etc. are called, log events identifying the function call and its callsite are emitted to <i>filename</i>. (more <a href="#Trace_Malloc">below</a>).<br>
</li><li> <b>Leaky</b> - This tool also dumps out stack traces (in a slightly different format) and can again be used to match up AddRefs with Releases in order to find missing Release calls. (more <a href="#Leaky">below</a>)
</li><li> <b>Menu items to interactively control Purify</b> - Interactively triggering a dump of all leaks or new leaks from within the running application is still one of the best ways to debug leaks in your subsystem. Menu items for this can be enabled for both viewer and apprunner. (more [{{mediawiki.external('#Purify|below')}}\)
</li></ul>
<p>More description on each of these will be provided below.
</p><p>Also see <a class="external" href="http://www.mozilla.org/performance/leak-brownbag.html">a newer overview</a> of what leak tools we have.
</p>
<h3 name="How_to_turn_on_refcnt.2Fmemory_logging"> How to turn on refcnt/memory logging </h3>
<p>Assuming you have a build with refcnt logging enabled (we'll tell you how to do that next), here's what you have to do to use it. All of the following environment variables can be set to any of these values:
</p>
<ul><li> <b>1</b> - log to stdout
</li><li> <b>2</b> - log to stderr
</li><li> <i><b>filename</b></i> - write log to a file
</li></ul>
<p>The log environment variables are:
</p>
<dl><dt>XPCOM_MEM_BLOAT_LOG
</dt></dl>
<dl><dd>If this environment variable is set then xpcom will use the "bloat" trackers. The bloat trackers gather data for the BloatView output that occurs when the program exits, when about:bloat is loaded, or a call to nsTraceRefcnt::DumpStatistics is made.
</dd></dl>
<dl><dd>When an addref/release/ctor/dtor call is made, the data is logged and attributed to the particular data type.
</dd></dl>
<dl><dd>By default enabling this environment variable will cause the BloatView software to dump out the entire database of collected data. If all you want to see is that data for objects that leaked, set the environment variable XPCOM_MEM_LEAK_LOG.
</dd></dl>
<dl><dt>XPCOM_MEM_LEAK_LOG
</dt></dl>
<dl><dd>This is basically a subset of XPCOM_MEM_BLOAT_LOG, and only shows classes that had object that were leaked, instead of statistics for all classes.
</dd></dl>
<dl><dt>XPCOM_MEM_REFCNT_LOG
</dt></dl>
<dl><dd>Setting this environment variable enables refcount tracing.<br> Only enable this for severe pain (unless you are using refcount tracing or leaky, see below). What this does is to enable logging (to stdout) of each and every call to addref/release without discrimination to the types involved. The output includes mapping the call-stacks at the time of the call to symbolic forms (on platforms that support this) and thus will be *very* *VERY* *VERY* slow. Did I say slow? It is not as slow when using XPCOM_MEM_LOG_CLASSES and XPCOM_MEM_LOG_OBJECTS
</dd></dl>
<dl><dt>XPCOM_MEM_COMPTR_LOG
</dt></dl>
<dl><dd>This environment variable enables logging of additions and releases of objects into nsCOMPtrs. This is currently only enabled on Linux.
</dd></dl>
<dl><dt>XPCOM_MEM_ALLOC_LOG
</dt></dl>
<dl><dd>For losing architectures (those that don't have stack-crawl software written for them), xpcom supports logging at the *call site* to AddRef/Release using the usual cpp __FILE__ and __LINE__ number macro expansion hackery. This results in slower code, but at least you get *some* data about where the leaks might be occurring from.
</dd></dl>
<dl><dt>XPCOM_MEM_LEAKY_LOG
</dt></dl>
<dl><dd>For platforms that support leaky, xpcom will endeavor to find at run time the symbols <code>__log_addref</code> and <code>__log_release</code> and if found, instead of doing the slow painful stack crawls at program execution time instead it will pass the buck to the leaky software. This will allow your program to actually run in user friendly real time, but does require that your platform support leaky. Currently only linux supports leaky.
</dd></dl>
<p>In addition, the following variable may be set to a list of class names:
</p>
<dl><dt>XPCOM_MEM_LOG_CLASSES
</dt></dl>
<dl><dd>Instead of slowing to a useless halt, instead you can slow to a mere crawl by using this option. When enabled, the xpcom logging software will look for the XPCOM_MEM_LOG_CLASSES environment variable (for platforms that support getenv). The variable contains a comma separated list of names which will be used to compare against the type's of the objects being logged. For example:
</dd></dl>
<pre class="eval"> env XPCOM_MEM_LOG_CLASSES=nsWebShell XPCOM_MEM_REFCNT_LOG=1 ./apprunner
</pre>
<dl><dd>will show you just the AddRef/Release calls to instances of nsWebShell while running apprunner. Note that setting XPCOM_MEM_LOG_CLASSES will also list the <i>serial number</i> of each object that leaked in the "bloat log" (that is, the file specified by the XPCOM_MEM_BLOAT_LOG variable). An object's serial number is simply a unique number, starting at one, that is assigned to the object when it is allocated. 
</dd></dl>
<p>You may use an object's serial number with the following variable to further restrict the reference count tracing:
</p>
<dl><dt>XPCOM_MEM_LOG_OBJECTS
</dt></dl>
<dl><dd>Set this variable to a comma-separated list of object <i>serial number</i> or ranges of <i>serial number</i>, e.g., <code>1,37-42,73,165</code>. When this is set, along with XPCOM_MEM_LOG_CLASSES and XPCOM_MEM_REFCNT_LOG, a stack track will be generated for <i>only</i> the specific objects that you list. For example,
</dd></dl>
<pre class="eval"> env XPCOM_MEM_LOG_CLASSES=nsWebShell XPCOM_MEM_LOG_OBJECTS=2 XPCOM_MEM_REFCNT_LOG=1 ./apprunner
</pre>
<dl><dd>will dump stack traces to the console for the 2nd <code>nsWebShell</code> object that gets allocated, and nothing else.
</dd></dl>
<p><br>
</p>
<h3 name="BloatView"> BloatView </h3>
<p>BloatView dumps out per-class statistics on allocations and refcounts, and provides gross numbers on the amount of memory being leaked broken down by class. Here's a sample of the BloatView output:
</p>
<pre class="eval">   BloatView: ALL (cumulative) LEAK AND BLOAT STATISTICS
    |&lt;------Class-----&gt;|&lt;-----Bytes------&gt;|&lt;----------------Objects----------------&gt;|&lt;--------------References--------------&gt;|
                         Per-Inst   Leaked    Total      Rem      Mean       StdDev     Total      Rem      Mean       StdDev
  0 TOTAL                     193  2480436   316271    12852 ( 5377.07  /-  5376.38)   410590    16079 ( 2850.93  /-  2849.79)
  1 StyleSetImpl               32        0        8        0 (    3.88  /-     3.15)     6304        0 (    7.18  /-     6.63)
  2 SinkContext                32        0       19        0 (    1.87  /-     1.04)        0        0 (    0.00  /-     0.00)
  3 nsXPCClasses               12        0        2        0 (    1.00  /-     0.71)       41        0 (    5.57  /-     4.98)
  4 NameSpaceURIKey             8       72      158        9 (    8.16  /-     7.62)        0        0 (    0.00  /-     0.00)
  5 nsSupportsArray            36    11304     2581      314 (  477.13  /-   476.53)     9223      314 (  579.23  /-   578.64)
  6 nsView                     96        0       57        0 (   27.64  /-    26.98)        0        0 (    0.00  /-     0.00)
  7 nsEnderDocumentObser       12        0        1        0 (    0.50  /-     0.87)        1        0 (    0.50  /-     0.87)
</pre>
<p>Here's how you interpret the columns:
</p>
<ul><li> <b>Class</b> - The name of the class in question. (Warning: The class name is truncated to 20 characters.)
</li><li> <b>Bytes Per-Inst</b> - The number of bytes returned if you were to write sizeof(<i>Class</i>). Note that this number does not reflect any memory held onto by the class, such as internal buffers, etc. (E.g. for nsStr -- you're seeing the size of the header struct, not the size of the string!)
</li><li> <b>Bytes Leaked</b> - The number of bytes per instance times the number of objects leaked (Bytes Per-Inst * Objects Rem). Use this number to look for the worst offenders. (Should be zero!)
</li><li> <b>Objects Total</b> - The total count of objects allocated of a given class.
</li><li> <b>Objects Rem</b> - The number of objects allocated of a given class that weren't deleted. (Should be zero!)
</li><li> <b>Objects Mean</b> - The mean (average) number of objects of a given class across the lifetime of the run. Data points are taken whenever new and delete are called (not at regular intervals).
</li><li> <b>Objects StdDev</b> - The standard deviation in the mean number of objects allocated.
</li><li> <b>References Total</b> - The total number of AddRefs performed on a given class.
</li><li> <b>References Rem</b> - The number of references on a given class that weren't Released. (Should be zero!)
</li><li> <b>References Mean</b> - The mean (average) number of references to a given class across the lifetime of the run. Data points are taken whenever AddRef and Release are called (not at regular intervals).
</li><li> <b>References StdDev</b> - The standard deviation in the mean number of references
</li></ul>
<p>Interesting things to look for:
</p>
<ul><li> <b>Are your classes in the list?</b> - Look! If they aren't, then you're not using the NS_IMPL_ADDREF and NS_IMPL_RELEASE (or NS_IMPL_ISUPPORTS which calls them) for xpcom objects, or MOZ_COUNT_CTOR and MOZ_COUNT_DTOR for non-xpcom objects. Not having your classes in the list is <i>not</i> ok. That means no one is looking at them, and we won't be able to tell if someone introduces a leak. (see {{mediawiki.external('#Instrumenting below')}} for how to fix this)
</li><li> <b>The Bytes Leaked for your classes should be zero!</b> - Need I say more? If it isn't, you should use the other tools to fix it.
</li><li> <b>The number of objects remaining might be equal to the total number of objects.</b> This could indicate a hand-written Release method (that doesn't use the NS_LOG_RELEASE macro from nsTraceRefcnt.h), or perhaps you're just not freeing any of the instances you've allocated. These sorts of leaks are easy to fix.
</li><li> <b>The total number of objects might be 1.</b> This might indicate a global variable or service. Usually this will have a large number of refcounts.
</li><li> <b>The number of refcounts might equal the total number of objects.</b> This class might be a candidate for a non-xpcom object (but be very cautious about changing this if it implements any interfaces besides nsISupports).
</li><li> <b>The mean number of objects is much lower than the total.</b> This indicates a few objects of this class are allocated and then freed, as opposed to the opposite case where there's a big build-up of instances that are all freed together (perhaps at the end of the program).
</li></ul>
<p>You can also dump out bloat statistics interactively by typing about:bloat in the location bar, or by using the menu items under the QA menu in debug builds. Note that you need to have the XPCOM_MEM_BLOAT_LOG or XPCOM_MEM_LEAK_LOG envirionment variable defined first. You can also type about:bloat?new to get a log since the last time you called it, or about:bloat?clear to clear the current set of statistics completely (use this option with caution as it can result in what look like negative refcounts, etc). Whenever these options are used, the log data is dumped to a file relative to the program's directory:
</p>
<pre class="eval"> bloatlogs/all-1999-10-16-010302.txt (a complete log resulting from the about:bloat command)
 bloatlogs/new-1999-10-16-010423.txt (an incremental log resulting from the about:bloat?new command)
</pre>
<h4 name="Viewing.2C_Sorting.2C_and_Comparing_Bloat_Logs"> Viewing, Sorting, and Comparing Bloat Logs </h4>
<p>You can view one or more bloat logs in your browser by running the following program:
</p>
<blockquote>
<code>perl</code> <code>mozilla/tools/memory/bloattable.pl</code> <i>log1</i> <i>log2</i> ... <i>logn</i> <code>&gt;</code> <i>htmlfile</i>
</blockquote>
<p>This will produce an HTML file that contains a table such as:
</p>
<div class="example">
<p><b>Byte Bloats</b>
</p>
<table border="1" cellspacing="1">
<tbody><tr>
<th> Name
</th><th> File
</th><th> Date
</th></tr>
<tr>
<td> blank
</td><td> <tt>blank.txt</tt>
</td><td> Tue Aug 29 14:17:40 2000
</td></tr>
<tr>
<td> mozilla
</td><td> <tt>mozilla.txt</tt>
</td><td> Tue Aug 29 14:18:42 2000
</td></tr>
<tr>
<td> yahoo
</td><td> <tt>yahoo.txt</tt>
</td><td> Tue Aug 29 14:19:32 2000
</td></tr>
<tr>
<td> netscape
</td><td> <tt>netscape.txt</tt>
</td><td> Tue Aug 29 14:20:14 2000
</td></tr></tbody></table>
<p>The numbers do not include <code>malloc</code> 'd data such as string contents.
</p><p>Click on a column heading to sort by that column. Click on a class name to see details for that class.
</p>
<table border="1" cellspacing="1">
<tbody><tr>
<th rowspan="2">
<p>{{mediawiki.external('javascript:reloadSelf(0,0) Class Name')}}
</p>
</th><th rowspan="2">
<p>{{mediawiki.external('javascript:reloadSelf(1,0) Instance&lt;br/&gt; Size')}}
</p>
</th><th colspan="5"> Bytes allocated
</th><th colspan="5"> Bytes allocated but not freed
</th></tr>
<tr>
<th>
<p>blank
</p>
</th><th>
<p>mozilla
</p>
</th><th>
<p>yahoo
</p>
</th><th>
<p>netscape
</p>
</th><th> Total
</th><th>
<p>blank
</p>
</th><th>
<p>mozilla
</p>
</th><th>
<p>yahoo
</p>
</th><th>
<p>netscape
</p>
</th><th>
<p>Total
</p>
</th></tr>
<tr>
<td>
<p>TOTAL
</p>
</td><td class="num"> <br>
</td><td class="neg"> <br>
</td><td class="neg"> <br>
</td><td class="neg"> <br>
</td><td class="neg"> <br>
</td><td class="num"> <br>
</td><td class="pos"> 1754408
</td><td class="pos"> 432556
</td><td class="pos"> 179828
</td><td class="pos"> 404184
</td><td class="num"> 2770976
</td></tr>
<tr>
<td>
<p>nsStr
</p>
</td><td class="num"> 20
</td><td class="pos"> 6261600
</td><td class="pos"> 3781900
</td><td class="pos"> 1120920
</td><td class="pos"> 1791340
</td><td class="num"> 12955760
</td><td class="pos"> 222760
</td><td class="pos"> 48760
</td><td class="pos"> 13280
</td><td class="pos"> 76160
</td><td class="num"> 360960
</td></tr>
<tr>
<td>
<p>nsHashKey
</p>
</td><td class="num"> 8
</td><td class="pos"> 610568
</td><td class="pos"> 1842400
</td><td class="pos"> 2457872
</td><td class="pos"> 1134592
</td><td class="num"> 6045432
</td><td class="pos"> 32000
</td><td class="pos"> 536
</td><td class="pos"> 568
</td><td class="pos"> 1216
</td><td class="num"> 34320
</td></tr>
<tr>
<td>
<p>nsTextTransformer
</p>
</td><td class="num"> 548
</td><td class="pos"> 8220
</td><td class="pos"> 469088
</td><td class="pos"> 1414936
</td><td class="pos"> 1532756
</td><td class="num"> 3425000
</td><td class="neg"> 0
</td><td class="neg"> 0
</td><td class="neg"> 0
</td><td class="neg"> 0
</td><td class="num"> 0
</td></tr>
<tr>
<td>
<p>nsStyleContextData
</p>
</td><td class="num"> 736
</td><td class="pos"> 259808
</td><td class="pos"> 325312
</td><td class="pos"> 489440
</td><td class="pos"> 338560
</td><td class="num"> 1413120
</td><td class="pos"> 141312
</td><td class="pos"> 220800
</td><td class="neg"> -11040
</td><td class="pos"> 94944
</td><td class="num"> 446016
</td></tr>
<tr>
<td>
<p>nsLineLayout
</p>
</td><td class="num"> 1100
</td><td class="pos"> 2200
</td><td class="pos"> 225500
</td><td class="pos"> 402600
</td><td class="pos"> 562100
</td><td class="num"> 1192400
</td><td class="neg"> 0
</td><td class="neg"> 0
</td><td class="neg"> 0
</td><td class="neg"> 0
</td><td class="num"> 0
</td></tr>
<tr>
<td>
<p>nsLocalFile
</p>
</td><td class="num"> 424
</td><td class="pos"> 558832
</td><td class="pos"> 19928
</td><td class="pos"> 1696
</td><td class="pos"> 1272
</td><td class="num"> 581728
</td><td class="pos"> 72080
</td><td class="pos"> 1272
</td><td class="pos"> 424
</td><td class="neg"> -424
</td><td class="num"> 73352
</td></tr></tbody></table>
</div>
<p>The first set of columns, <b>Bytes allocated</b>, shows the amount of memory allocated for the first log file (<tt>blank.txt</tt>), the difference between the first log file and the second (<tt>mozilla.txt</tt>), the difference between the second log file and the third (<tt>yahoo.txt</tt>), the difference between the third log file and the fourth (<tt>netscape.txt</tt>), and the total amount of memory allocated in the fourth log file. These columns provide an idea of how hard the memory allocator has to work, but they do not indicate the size of the working set.
</p><p>The second set of columns, <b>Bytes allocated but not freed</b>, shows the net memory gain or loss by subtracting the amount of memory freed from the amount allocated.
</p><p>The <b>Show Objects</b> and <b>Show References</b> buttons show the same statistics but counting objects or AddRef'd references rather than bytes.
</p>
<h4 name="Comparing_Bloat_Logs"> Comparing Bloat Logs </h4>
<p>You can also compare any two bloat logs (either those produced when the program shuts down, or written to the bloatlogs directory) by running the following program:
</p>
<blockquote>
<code>perl mozilla/tools/tinderbox/bloatdiff.pl</code> &lt;previous-log&gt; &lt;current-log&gt;
</blockquote>
<p>This will give you output of the form:
</p>
<pre class="eval"> Bloat/Leak Delta Report
 Current file:  dist/win32_D.OBJ/bin/bloatlogs/all-1999-10-22-133450.txt
 Previous file: dist/win32_D.OBJ/bin/bloatlogs/all-1999-10-16-010302.txt
 --------------------------------------------------------------------------
 CLASS                     LEAKS       delta      BLOAT       delta
 --------------------------------------------------------------------------
 TOTAL                   6113530       2.79%   67064808       9.18%
 StyleContextImpl         265440      81.19%     283584     -26.99%
 CToken                   236500      17.32%     306676      20.64%
 nsStr                    217760      14.94%    5817060       7.63%
 nsXULAttribute           113048     -70.92%     113568     -71.16%
 LiteralImpl               53280      26.62%      75840      19.40%
 nsXULElement              51648       0.00%      51648       0.00%
 nsProfile                 51224       0.00%      51224       0.00%
 nsFrame                   47568     -26.15%      48096     -50.49%
 CSSDeclarationImpl        42984       0.67%      43488       0.67%
</pre>
<p>This "delta report" shows the leak offenders, sorted from most leaks to fewest. The delta numbers show the percentage change between runs for the amount of leaks and amount of bloat (negative numbers are better!). The bloat number is a metric determined by multiplying the total number of objects allocated of a given class by the class size. Note that although this isn't necessarily the amount of memory consumed at any given time, it does give an indication of how much memory we're consuming. The more memory in general, the worse the performance and footprint. The percentage 99999.99% will show up indicating an "infinite" amount of leakage. This happens when something that didn't leak before is now leaking.
</p>
<h4 name="Bloat_Statistics_on_Tinderbox"> Bloat Statistics on Tinderbox </h4>
<p>Each build rectangle on Tinderbox will soon be capable of displaying the total leaks delta and bloat delta percentages from one build to the next. Horray!<br><br>
</p>
<table border="1" width="100">
<tbody><tr>
<td> <span><u>warren</u></span>
</td><td style="background-color: #0C0"> <span><u>L</u></span> <span><u>C</u></span><br> L:-3 <br> B: 21
</td></tr></tbody></table>
<p>Hmmm. Warren checked in and the number of leaks went down by 3%. (Yes!) But the amount of bloat went up by 21%. (Ouch!) This probably should be investigated further. Sometimes bloat can go up because new features were added that just take up more memory (or if the set of test URLs were changed, and the activity is different from last time), but in general we'd like to see both of these numbers continue to go down. You can look at the end of the log (by clicking on the L) to see the bloat statistics and delta report for a breakdown of what actually happened.
</p>
<h3 name="Boehm_GC_Leak_Detector"> Boehm GC Leak Detector </h3>
<p>more...<br>
</p><p><br>
</p>
<h3 name="Refcount_Tracing"> Refcount Tracing </h3>
<p>Refcount tracing is used to capture stack traces of AddRef and Release calls to use with the Refcount Balancer. It is best to set the XPCOM_MEM_REFCNT_LOG environment variable to point to a file when using it.
</p><p>See <a class="external" href="http://www.mozilla.org/performance/refcnt-balancer.html">Refcount Balancer</a> for more information. Also see the <a class="external" href="http://mozilla.org/performance/leak-tutorial.html">tutorial on finding leaks of XPCOM objects</a>.
</p><p><br>
</p>
<h3 name="Trace_Malloc"> Trace Malloc </h3>
<p>TraceMalloc captures stack traces of all <tt>malloc</tt>, <tt>calloc</tt> , <tt>realloc</tt>, and <tt>free</tt> calls (this currently covers all <tt>operator new</tt> and <tt>delete</tt> calls in Mozilla, too). To enable TraceMalloc in your build, configure with <code>--enable-trace-malloc</code>. Run the resulting mozilla with <code>--trace-malloc</code> <i>filename</i> as an argument, and a binary log of events and callsite relations will be written to <i>filename</i> . If <i>filename</i> is <code>-</code>, nothing is written, but the TraceMalloc machinery keeps track of all live allocations, and builds its tree of callsites to keep book on stack backtraces.
</p><p>Tools such as bloatblame (<tt>tools/trace-malloc/bloatblame.c</tt>) can be used to process <i>filename</i>. Try running with the unified output format option, <code>-u</code>. The output is a large HTML file that hyperlinks ancestor and descendent libraries, classes, and functions that call into one another, attributing <code>malloc</code> blame up and down each graph. Bloatblame accumulates allocation counts, and ignores <code>free</code> calls.
</p><p>If you run with <code>--trace-malloc -</code>, your code can call NS_TraceMallocDumpAllocations(<i>pathname</i>) at opportune times, and a human-readable listing of the current heap, including stack traces for every allocation, will be written to <i>pathname</i>. This file can be post-processed by tools in <a class="external" href="http://lxr.mozilla.org/mozilla/source/tools/trace-malloc">mozilla/tools/trace-malloc</a> as follows:
</p>
<ul><li> <a class="external" href="http://lxr.mozilla.org/mozilla/source/tools/trace-malloc/histogram.pl">histogram.pl</a>, which produces a type histogram that can be diffed with <a class="external" href="http://lxr.mozilla.org/mozilla/source/tools/trace-malloc/histogram-diff.sh">histogram-diff.sh</a> to produce output that looks like this:
</li><li> **  
</li></ul>
<pre class="eval">                        ---- 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
</pre>
<ul><li> <a class="external" href="http://lxr.mozilla.org/mozilla/source/tools/trace-malloc/uncategorized.pl">uncategorized.pl</a>, which lists all the void* allocations (the ones that couldn't be categorized by type), sorted by size.
</li></ul>
<p>Also, your JavaScript can call the following DOM window methods:
</p>
<ul><li> <tt>TraceMallocDisable()</tt> - turn off tracing, first flushing any buffered log events for all log files.
</li><li> <tt>TraceMallocEnable()</tt> - turn on tracing.
</li><li> <tt>TraceMallocOpenLogFile(<i>filename</i>)</tt> - open a new log file and return its log file descriptor (or -1 on error).
</li><li> <tt>TraceMallocChangeLogFD(<i>logfd</i>)</tt> - change the current log file to the one identified by <i>logfd</i>, returning the previous fd (so you can maintain a number of open files; keep their fds in a JS Array!).wa
</li><li> <tt>TraceMallocCloseLogFD(<i>logfd</i>)</tt> - close the log file identified by <i>logfd</i>, flushing its buffer of any events first. If <i>logfd</i> identifies the current log file, change the current log file to the default log file given by the --trace-malloc command line argument.
</li><li> <tt>TraceMallocLogTimestamp(<i>caption</i>)</tt> - log a timestamp event to the current log file, annotating the log even with the <i>caption</i> string.
</li><li> <tt>TraceMallocDumpAllocations(<i>pathname</i>)</tt> - dump a human-readable listing of all traced, live allocations.
</li></ul>
<p>See <a class="external" href="http://lxr.mozilla.org/mozilla/source/xpcom/base/nsTraceMalloc.h">nsTraceMalloc.h</a> for detailed comments on the log file format.<br>
</p>
<h3 name="Leaky"> Leaky </h3>
<h4 name="Using_this_stuff_with_leaky"> Using this stuff with leaky </h4>
<p>First, setup these environment variables:
</p>
<pre class="eval"> setenv LD_PRELOAD ../lib/libleaky.so   #assumes you execute apprunner/viewer in the dist/bin directory
 setenv LIBMALLOC_LOG 8                 #tells leaky to log addref/release calls
 setenv XPCOM_MEM_LEAKY_LOG 1           #use leaky
 setenv XPCOM_MEM_LOG_CLASSES "a,b,c"   #the list of types you care about
</pre>
<p>Then run the viewer or the apprunner and run your test. Then exit it. The result will be some large file in your current directory called <tt>malloc-log</tt> and a small file called <tt>malloc-map</tt>. If these aren't there then something's wrong.
</p><p>If it works properly, then you now have the tracing data for the problem you are chasing in malloc-log. Use leaky to convert it to human readable form and debug away:
</p>
<blockquote>
<code>leaky -dRq &lt;viewer|apprunner&gt; malloc-log &gt; /tmp/log</code>
</blockquote>
<p>Leaky used to require c filt, but now it does it itself. With the -R option, leaky will only log the refcnts that actually leaked (those that didn't go to zero).
</p>
<h4 name="Leaky_environment_variables"> Leaky environment variables </h4>
<dl><dt>LD_PRELOAD
</dt></dl>
<dl><dd>Set this to the pathname to libleaky.so if you are using leaky to track memory operations.
</dd></dl>
<dl><dt>LIBMALLOC_LOG
</dt></dl>
<dl><dd>Set this to "8" to enable leaky to track addref/release calls that are logged by xpcom. Note that you must set bit 8 in xpcomrefcnt to connect xpcom's tracing to leakys tracing.
</dd></dl>
<h4 name="Sample_output"> Sample output </h4>
<p>Here is what you see when you enable some logging with XPCOM_MEM_LOG_CLASSES set to something:
</p><p><br>
</p>
<pre class="eval"> nsWebShell      0x81189f8       Release 5
 nsWebShell::Release(void) 0x59
 nsCOMPtr&lt;nsIContentViewerContainer&gt;::~nsCOMPtr(void) 0x34
 nsChannelListener::OnStartRequest(nsIChannel *, nsISupports *) 0x550
 nsFileChannel::OnStartRequest(nsIChannel *, nsISupports *) 0x7b
 nsOnStartRequestEvent::HandleEvent(void) 0x46
 nsStreamListenerEvent::HandlePLEvent(PLEvent *) 0x62
 PL_HandleEvent 0x57
 PL_ProcessPendingEvents 0x90
 nsEventQueueImpl::ProcessPendingEvents(void) 0x1d
 nsAppShell::SetDispatchListener(nsDispatchListener *) 0x3e
 gdk_get_show_events 0xbb
 g_io_add_watch 0xaa
 g_get_current_time 0x136
 g_get_current_time 0x6f1
 g_main_run 0x81
 gtk_main 0xb9
 nsAppShell::Run(void) 0x245
 nsAppShell::Run(void) 0xc7a92ede
 nsAppShell::Run(void) 0xc7a9317c
 __libc_start_main 0xeb
</pre>
<p>Here is what you see when you use the leaky tool to dump out addref/release leaks:
</p><p>addref 082cccc8 0 00000001 --&gt; CViewSourceHTML::AddRef(void) CViewSourceHTML::QueryInterface(nsID &amp;, void **) NS_NewViewSourceHTML(nsIDTD **) .LM708 GetSharedObjects(void) nsParser::RegisterDTD(nsIDTD *) RDFXMLDataSourceImpl::Refresh(int) nsChromeRegistry::InitRegistry(void) nsChromeProtocolHandler::NewChannel(char *, nsIURI *, nsILoadGroup *, nsIEventSinkGetter *, nsIChannel **) nsIOService::NewChannelFromURI(char *, nsIURI *, nsILoadGroup *, nsIEventSinkGetter *, nsIChannel **) NS_OpenURI(nsIChannel **, nsIURI *, nsILoadGroup *, nsIEventSinkGetter *) NS_OpenURI(nsIInputStream **, nsIURI *) CSSLoaderImpl::LoadSheet(URLKey &amp;, SheetLoadData *) CSSLoaderImpl::LoadChildSheet(nsICSSStyleSheet *, nsIURI *, nsString &amp;, int, int) CSSParserImpl::ProcessImport(int &amp;, nsString &amp;, nsString &amp;) CSSParserImpl::ParseImportRule(int &amp;) CSSParserImpl::ParseAtRule(int &amp;) CSSParserImpl::Parse(nsIUnicharInputStream *, nsIURI *, nsICSSStyleSheet *&amp;) CSSLoaderImpl::ParseSheet(nsIUnicharInputStream *, SheetLoadData *, int &amp;, nsICSSStyleSheet *&amp;) CSSLoaderImpl::LoadAgentSheet(nsIURI *, nsICSSStyleSheet *&amp;, int &amp;, void (*)(nsICSSStyleSheet *, void *), void *) nsLayoutModule::Initialize(void) nsLayoutModule::GetClassObject(nsIComponentManager *, nsID &amp;, nsID &amp;, void **) nsNativeComponentLoader::GetFactoryFromModule(nsDll *, nsID &amp;, nsIFactory **) nsNativeComponentLoader::GetFactory(nsID &amp;, char *, char *, nsIFactory **) .LM1381 nsComponentManagerImpl::FindFactory(nsID &amp;, nsIFactory **) nsComponentManagerImpl::CreateInstance(nsID &amp;, nsISupports *, nsID &amp;, void **) nsComponentManager::CreateInstance(nsID &amp;, nsISupports *, nsID &amp;, void **) RDFXMLDataSourceImpl::Refresh(int) nsChromeRegistry::InitRegistry(void) nsChromeProtocolHandler::NewChannel(char *, nsIURI *, nsILoadGroup *, nsIEventSinkGetter *, nsIChannel **) nsIOService::NewChannelFromURI(char *, nsIURI *, nsILoadGroup *, nsIEventSinkGetter *, nsIChannel **) NS_OpenURI(nsIChannel **, nsIURI *, nsILoadGroup *, nsIEventSinkGetter *) nsDocumentBindInfo::Bind(nsIURI *, nsILoadGroup *, nsIInputStream *, unsigned short *) nsDocLoaderImpl::LoadDocument(nsIURI *, char *, nsIContentViewerContainer *, nsIInputStream *, nsISupports *, unsigned int, unsigned int, unsigned short *) nsWebShell::DoLoadURL(nsIURI *, char *, nsIInputStream *, unsigned int, unsigned int, unsigned short *) nsWebShell::LoadURI(nsIURI *, char *, nsIInputStream *, int, unsigned int, unsigned int, nsISupports *, unsigned short *) nsWebShell::LoadURL(unsigned short *, char *, nsIInputStream *, int, unsigned int, unsigned int, nsISupports *, unsigned short *) nsWebShell::LoadURL(unsigned short *, nsIInputStream *, int, unsigned int, unsigned int, nsISupports *, unsigned short *) nsWebShellWindow::Initialize(nsIWebShellWindow *, nsIAppShell *, nsIURI *, int, int, nsIXULWindowCallbacks *, int, int, nsWidgetInitData &amp;) nsAppShellService::JustCreateTopWindow(nsIWebShellWindow *, nsIURI *, int, int, unsigned int, nsIXULWindowCallbacks *, int, int, nsIWebShellWindow **) nsAppShellService::CreateTopLevelWindow(nsIWebShellWindow *, nsIURI *, int, int, unsigned int, nsIXULWindowCallbacks *, int, int, nsIWebShellWindow **) OpenChromURL(char *, int, int) HandleBrowserStartup(nsICmdLineService *, nsIPref *, int) DoCommandLines(nsICmdLineService *, int) main1(int, char **) main __libc_start_main
</p><p><br>
</p>
<h3 name="Purify"> Purify </h3>
<p>more...
</p>
<h3 name="How_to_build_xpcom_with_refcnt.2Fmemory_logging"> How to build xpcom with refcnt/memory logging </h3>
<p>Built into xpcom is the ability to support the debugging of memory leaks. By default, an optimized build of xpcom has this disabled. Also by default, the debug builds have the logging facilities enabled. You can control either of these options by changing environment variables before you build mozilla:
</p>
<dl><dt>FORCE_BUILD_REFCNT_LOGGING
</dt></dl>
<dl><dd>If this is defined then regardless of the type of build, refcnt logging (and related memory debugging) will be enabled in the build.
</dd></dl>
<dl><dt>NO_BUILD_REFCNT_LOGGING
</dt></dl>
<dl><dd>If this is defined then regardless of the type of build or of the setting of the FORCE_BUILD_REFCNT_LOGGING, no refcnt logging will be enabled and no memory debugging will be enabled. This variable overrides FORCE_BUILD_REFCNT_LOGGING.
</dd></dl>
<p>The remaining discussion assumes that one way or another that xpcom has been built with refcnt/memory logging enabled.
</p>
<h3 name="How_to_instrument_your_objects_for_refcnt.2Fmemory_logging"> How to instrument your objects for refcnt/memory logging </h3>
<p>First, if your object is an xpcom object and you use the NS_IMPL_ADDREF and NS_IMPL_RELEASE (or a variation thereof) macro to implement your AddRef and Release methods, then there is nothing you need do. By default, those macros support refcnt logging directly.
</p><p>If your object is not an xpcom object then some manual editing is in order. The following sample code shows what must be done:
</p>
<pre class="eval"> MyType::MyType()
 {
     MOZ_COUNT_CTOR(MyType);
 }
</pre>
<pre class="eval"> MyType::~MyType()
 {
     MOZ_COUNT_DTOR(MyType);
 }
</pre>
<p><br>
</p>
<h3 name="What_are_those_macros_doing_for_me_anyway.3F"> What are those macros doing for me anyway? </h3>
<p><code>NS_IMPL_ADDREF</code> has this additional line in it:
</p>
<pre class="eval"> NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this));
</pre>
<p>What this is doing is logging the <code>AddRef</code> call using XPCOM's <code>nsTraceRefcnt</code> class. The implementation of that macro is:
</p>
<pre class="eval"> #define NS_LOG_ADDREF(_p, _rc, _type, _size) \
     nsTraceRefcnt::LogAddRef((_p), (_rc), (_type), (PRUint32) (_size))
</pre>
<p>Which as you can see just passes the buck to nsTraceRefcnt. nsTraceRefcnt implements the logging support and will track addref/release/ctor/dtor calls in a database that it builds up as the program is executing. In a similar manner, NS_IMPL_RELEASE uses NS_LOG_RELEASE which uses <code>nsTraceRefcnt::LogRelease</code>.
</p><p>For the <code>MOZ_COUNT_CTOR</code> and <code>MOZ_COUNT_DTOR</code> macros the expansion boils down to calls to <code>nsTraceRefcnt::LogCtor</code> and <code>nsTraceRefcnt::LogDtor</code> calls. Again, the type of the object is passed in as well as the sizeof of all the data type.
</p>
<pre class="eval"> #define MOZ_COUNT_CTOR(_type) \
     PR_BEGIN_MACRO \
         nsTraceRefcnt::LogCtor((void*)this, #_type, sizeof(*this)); \
     PR_END_MACRO
</pre>
<pre class="eval"> #define MOZ_COUNT_DTOR(_type) \
     PR_BEGIN_MACRO \
         nsTraceRefcnt::LogDtor((void*)this, #_type, sizeof(*this));
     PR_END_MACRO
</pre>
<div class="originaldocinfo">
<h2 name="Original_Document_Information"> Original Document Information </h2>
<ul><li> Author(s): unknown
</li><li> Last Updated Date: August 17, 2006
</li><li> Copyright Information: Portions of this content are © 1998–2007 by individual mozilla.org contributors; content available under a Creative Commons license.
</li></ul>
</div>
Revert to this revision