You are currently viewing a snapshot of www.mozilla.org taken on April 21, 2008. Most of this content is highly out of date (some pages haven't been updated since the project began in 1998) and exists for historical purposes only. If there are any pages on this archive site that you think should be added back to www.mozilla.org, please file a bug.


How to find leaks of XPCOM objects

[ Up to Tools, Performance ]

The sections later in this document on object graphs that include JavaScript objects are somewhat out of date (since the XPCDOM landing). See the leak brownbag for more up-to-date information. —November 2001


This document describes how to find leaks of XPCOM objects using the XPCOM logging facilities in nsTraceRefcnt along with the refcount balancer. These tools are most easily used on Linux. The stack tracing tools do not work on Windows and the nsCOMPtr logging facilities are not yet enabled on Windows or Macintosh. They are built by default in debug builds of Mozilla. The Perl scripts used are available by checking out mozilla/tools/rb.

This document includes examples of how I would debug a leak (on Linux). The environment variables that I set are cumulative. The example chosen is intentionally one of the most difficult class of leaks so that I can demonstrate lots of tools (by heading down the wrong path). Most leaks are much easier.

This is not intended to be a full description of what these tools can do. See the XPCOM memory tools documentation and the refcount balancer documentation for more details.

See the leak brownbag for an more general overview of how to find leaks in Mozilla, including information on other, newer, tools.

What leaked?

The XPCOM leak logging tools show leaks and bloat for certain objects: XPCOM objects (which use the NS_IMPL_ADDREF and NS_IMPL_RELEASE macros) and any other objects that use the MOZ_COUNT_CTOR and MOZ_COUNT_DTOR macros. They don't know anything about any other objects or about string buffers. The objects detected are leaked objects, objects held in static variables, and anything those objects own. XPCOM objects whose AddRef method is never called are not included.

To see the XPCOM objects leaked, set the environment variable XPCOM_MEM_LEAK_LOG to a filename (or to 1 for standard output):

> setenv XPCOM_MEM_LEAK_LOG 1
> ./mozilla -editor
     |<----------------Class--------------->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|
                                              Per-Inst   Leaked    Total      Rem      Mean       StdDev     Total      Rem      Mean       StdDev
   0 TOTAL                                          26    51820   443674     1368 ( 6208.07 +/-  4498.40)  1314903     1041 ( 3261.06 +/-  3649.33)
nsTraceRefcnt::DumpStatistics: 460 entries
   1 ArenaImpl                                      48       48       11        1 (    5.76 +/-     3.11)       23        1 (    6.02 +/-     3.16)
   2 AtomImpl                                       16     3184     2646      199 ( 1056.26 +/-   477.20)   152742      313 ( 6642.19 +/-  2149.30)
  15 CSSDeclarationImpl                             76      456      973        6 (  481.05 +/-   276.96)     2204       17 (  638.81 +/-   351.72)
  17 CSSLoaderImpl                                 140      140       14        1 (    4.59 +/-     3.53)      105        1 (    8.05 +/-     6.65)
  18 CSSParserImpl                                 252      252       82        1 (    0.70 +/-     0.76)      304        1 (    1.45 +/-     0.88)
  20 CSSStyleSheetImpl                              96      192       40        2 (   20.50 +/-    11.34)      352        3 (   60.57 +/-    32.74)
  21 CSSStyleSheetInner                             40       80       36        2 (   18.50 +/-    10.18)        0        0 (    0.00 +/-     0.00)
  41 GIFDecoder                                     16       16       47        1 (   23.13 +/-    12.67)       94        1 (   23.51 +/-    12.72)
  42 GenericTableRule                               16       32       22        2 (   11.50 +/-     6.15)       22        2 (   11.50 +/-     6.15)
  43 GlobalWindowImpl                              208      624        3        3 (    2.00 +/-     1.00)    17587        4 (   11.45 +/-     3.00)
  44 HTMLAttribute                                  16       32       23        2 (   12.00 +/-     6.44)        0        0 (    0.00 +/-     0.00)
  45 HTMLAttributesImpl                             60       60        9        1 (    4.76 +/-     2.54)        9        1 (    4.76 +/-     2.54)
  46 HTMLCSSStyleSheetImpl                          32       32       11        1 (    5.76 +/-     3.11)       64        2 (   15.67 +/-     9.03)
  47 HTMLColorRule                                  20       20        3        1 (    1.80 +/-     0.84)        7        1 (    3.15 +/-     1.34)
  49 HTMLStyleSheetImpl                             60       60       11        1 (    5.76 +/-     3.11)       78        2 (   16.10 +/-     8.96)
  52 ImageConsumer                                  64       64       47        1 (   15.80 +/-    11.06)     1269        3 (   50.27 +/-    33.17)
  55 ImageNetContextImpl                            32       32       95        1 (   46.90 +/-    26.19)      142        2 (   62.78 +/-    31.17)
  56 ImageRendererImpl                              12       12        1        1 (    1.00 +/-     0.00)       48        1 (   23.83 +/-    13.21)
  59 ImageURLImpl                                   24       24       47        1 (   15.80 +/-    11.06)       94        2 (   31.59 +/-    22.05)
  60 ImgDCallbk                                     16       16       47        1 (   23.32 +/-    12.91)       47        1 (   23.32 +/-    12.91)
  70 LocationImpl                                   28       28        1        1 (    1.00 +/-     0.00)       17        2 (    2.75 +/-     0.76)
  75 NameSpaceImpl                                  28      140      155        5 (   50.36 +/-    35.24)    14101       39 ( 1306.49 +/-   781.99)
  76 NameSpaceManagerImpl                           12       72       75        6 (   20.44 +/-    12.14)      405       10 (   61.25 +/-    42.47)
  77 NameSpaceURIKey                                 8       96      136       12 (   11.20 +/-     2.18)        0        0 (    0.00 +/-     0.00)
  78 NavigatorImpl                                  28       28        1        1 (    1.00 +/-     0.00)        7        1 (    2.54 +/-     0.97)
  79 NetReaderImpl                                  16       16       47        1 (   15.80 +/-    11.06)      235        1 (   16.50 +/-    11.03)
  90 RDFServiceImpl                                 52       52        1        1 (    1.00 +/-     0.00)      705        3 (  117.61 +/-    54.04)
 103 URLKey                                         12       24      148        2 (   18.30 +/-     9.60)        0        0 (    0.00 +/-     0.00)
 125 nsAsyncStreamListener                          24       24      113        1 (   10.63 +/-    10.81)        0        0 (    0.00 +/-     0.00)
 126 nsAsyncStreamObserver                          20       20      113        1 (   10.63 +/-    10.81)      927        1 (   29.00 +/-    31.96)
 127 nsAtomList                                      8       64     2029        8 (  331.84 +/-   211.01)        0        0 (    0.00 +/-     0.00)
 128 nsAttrSelector                                 40      320     1027        8 (  187.30 +/-   111.31)        0        0 (    0.00 +/-     0.00)
 132 nsBaseComposerCommand                          12      396       33       33 (   17.00 +/-     9.67)      287       35 (   34.83 +/-     5.18)
 134 nsBaseEditorCommand                            12       96        8        8 (    4.50 +/-     2.45)      250       42 (   41.03 +/-     7.25)
 138 nsBasicEncoder                                 16       16        1        1 (    1.00 +/-     0.00)     1462        1 (    4.16 +/-     0.70)
 139 nsBindingManager                               20       20       11        1 (    5.76 +/-     3.11)    14223        1 (    7.92 +/-     3.64)
 141 nsBoxLayout                                    12       36        3        3 (    2.00 +/-     1.00)     1481        3 (  179.23 +/-    79.70)
 142 nsCSSColor                                     72      216      292        3 (  146.75 +/-    83.94)        0        0 (    0.00 +/-     0.00)
 149 nsCSSMargin                                    64      192      390        3 (  195.75 +/-   112.22)        0        0 (    0.00 +/-     0.00)
 150 nsCSSPosition                                  80       80       96        1 (   48.25 +/-    27.64)        0        0 (    0.00 +/-     0.00)
 151 nsCSSRect                                      32      256     1050        8 (  526.99 +/-   302.04)        0        0 (    0.00 +/-     0.00)
 152 nsCSSRule                                      16      272     1238       17 (  623.22 +/-   355.04)    16905       17 ( 3369.22 +/-  1353.03)
 154 nsCSSSelector                                  32      800     5620       25 (  863.02 +/-   499.64)        0        0 (    0.00 +/-     0.00)
 155 nsCSSTable                                     52       52        5        1 (    2.78 +/-     1.39)        0        0 (    0.00 +/-     0.00)
 158 nsCSSValueList                                 12       24       51        2 (   26.00 +/-    14.51)        0        0 (    0.00 +/-     0.00)
 171 nsClassList                                     8        8      657        1 (  328.26 +/-   189.15)        0        0 (    0.00 +/-     0.00)
 181 nsContentList                                  64       64        7        1 (    2.69 +/-     1.18)       21        1 (    3.54 +/-     1.45)
 184 nsControllerCommandManager                     32       64        2        2 (    1.50 +/-     0.71)       21        2 (    3.05 +/-     1.50)
 188 nsDNSService                                   68       68        1        1 (    1.00 +/-     0.00)        4        1 (    1.71 +/-     0.76)
 190 nsDOMAttributeMap                              24       48       22        2 (   11.50 +/-     6.15)      238        2 (   14.02 +/-     6.50)
 191 nsDOMDocumentType                             160      320        4        2 (    2.50 +/-     1.05)       39        3 (    5.12 +/-     2.16)
 194 nsDOMImplementation                            28       28        4        1 (    0.57 +/-     0.53)        9        1 (    1.24 +/-     0.83)
criptObjectFactory                       12       12        1        1 (    1.00 +/-     0.00)      367        1 (    2.05 +/-     0.71)
 197 nsDOMWindowController                          16       32        2        2 (    1.50 +/-     0.71)       23        2 (    2.64 +/-     0.97)
 201 nsDateTimeFormatUnix                          156      156        1        1 (    1.00 +/-     0.00)        2        1 (    1.33 +/-     0.58)
 206 nsDocLoaderImpl                               132      132        4        1 (    2.29 +/-     1.11)     1661        3 (   48.56 +/-    36.21)
 211 nsDocument                                    224      224       10        1 (    5.26 +/-     2.83)     1835        1 (   14.16 +/-     5.43)
 212 nsDocumentOpenInfo                             56       56       51        1 (   15.53 +/-    11.45)      153        1 (   16.46 +/-    11.45)
 213 nsDrawingSurfaceGTK                           112      112       63        1 (    1.51 +/-     0.55)       63        1 (    1.51 +/-     0.55)
 217 nsEditorController                             28       56        3        2 (    2.00 +/-     0.82)     1083        2 (   11.10 +/-     1.58)
 225 nsEventListenerManager                         80      400      784        5 (  287.12 +/-   137.44)     5615        5 (  350.63 +/-   156.52)
 226 nsEventQueueImpl                               36       36        1        1 (    1.00 +/-     0.00)     1738        5 (   46.21 +/-    34.61)
 227 nsEventQueueServiceImpl                        28       28        1        1 (    1.00 +/-     0.00)      552        2 (   25.12 +/-    23.52)
 232 nsFileChannel                                 120      120      176        1 (    7.94 +/-     9.52)     2652        5 (   59.75 +/-    65.17)
 233 nsFileIO                                       32       32      176        1 (    0.65 +/-     0.62)     1232        1 (    1.65 +/-     0.82)
 238 nsFileStream                                   20       20      176        1 (    0.67 +/-     0.67)      586        1 (    1.45 +/-     0.95)
 239 nsFileTransport                               140      140      179        1 (    7.45 +/-     9.59)     1443        2 (   58.16 +/-    72.78)
 240 nsFileTransportService                         28       28        1        1 (    1.00 +/-     0.00)      362        1 (    2.99 +/-     0.72)
 246 nsGenericDOMNodeList                           20       20        2        1 (    1.33 +/-     0.58)       90        1 (    2.93 +/-     0.76)
 247 nsGenericFactory                               20       20      140        1 (   70.25 +/-    40.34)     2953        2 (  189.14 +/-    55.19)
 251 nsHTMLBRElement                                48       48        2        1 (    1.33 +/-     0.58)     1173        1 (    8.81 +/-     2.47)
 252 nsHTMLBodyElement                              64       64        3        1 (    1.80 +/-     0.84)     2964        1 (   18.74 +/-     5.24)
 256 nsHTMLHeadElement                              52       52        3        1 (    1.80 +/-     0.84)      227        1 (    5.08 +/-     1.67)
 257 nsHTMLHtmlElement                              52       52        3        1 (    1.80 +/-     0.84)      837        1 (   10.40 +/-     3.08)
 265 nsHashKey                                       4      688    48981      172 ( 2899.56 +/-   866.84)        0        0 (    0.00 +/-     0.00)
 266 nsHashtable                                    12      204      319       17 (  153.00 +/-    85.00)        0        0 (    0.00 +/-     0.00)
 268 nsIOService                                    28       28        1        1 (    1.00 +/-     0.00)     1168        1 (    4.85 +/-     1.03)
 269 nsImageGTK                                     96       96       47        1 (   23.13 +/-    12.67)      300        1 (   81.30 +/-    34.02)
 276 nsJSEventListener                              32       32      665        1 (  247.23 +/-   115.23)     1341        1 (  249.11 +/-   115.94)
 289 nsLoadGroup                                     4        4        4        1 (    2.29 +/-     1.11)      848        3 (   26.97 +/-    21.51)
 290 nsLocalFile                                   116      116     1071        1 (  121.48 +/-    41.61)     6121        3 (  130.95 +/-    50.57)
 300 nsMemoryImpl                                   16       16        1        1 (    1.00 +/-     0.00)      345        1 (   11.95 +/-    10.59)
 310 nsNoAuthURLParser                              12       12        1        1 (    1.00 +/-     0.00)      743        9 (   43.19 +/-    36.96)
 311 nsNodeInfo                                     28      588      379       21 (  182.15 +/-    98.64)    27438       85 ( 4818.27 +/-  2929.00)
 312 nsNodeInfoManager                              20       40       11        2 (    6.00 +/-     2.99)     6885       22 (  232.95 +/-    96.37)
 322 nsPipe                                         88       88      113        1 (    9.48 +/-    10.62)      589        2 (   10.72 +/-    10.40)
 331 nsProxyEventClass                              36       72        3        2 (    2.00 +/-     0.82)      391        2 (   35.40 +/-    22.48)
 332 nsProxyEventObject                            188      376       97        2 (   31.67 +/-    22.30)      245        2 (   32.26 +/-    22.45)
 333 nsProxyObject                                  28       56       97        2 (   31.67 +/-    22.30)      388        2 (   62.16 +/-    44.84)
 346 nsRepeatService                                20       20        1        1 (    1.00 +/-     0.00)        2        1 (    1.33 +/-     0.58)
 347 nsResChannel                                  100      100      147        1 (    8.25 +/-     9.89)     1029        1 (    9.86 +/-     9.87)
 348 nsResProtocolHandler                           28       28        1        1 (    1.00 +/-     0.00)      886        1 (   10.02 +/-     9.89)
 360 nsSimpleURI                                     4        4        6        1 (    2.36 +/-     1.12)      291        4 (   20.82 +/-     8.53)
 361 nsSliderMediator                               20       40        8        2 (    4.50 +/-     2.14)       16        2 (    7.97 +/-     3.78)
 362 nsSocketTransportService                       64       64        1        1 (    1.00 +/-     0.00)        6        2 (    2.50 +/-     0.85)
 367 nsStdURL                                        4       56     1086       14 (  108.12 +/-    75.62)    10047       18 (  237.31 +/-   150.06)
 368 nsStdURLParser                                 12       12        1        1 (    1.00 +/-     0.00)     1793        5 (   56.42 +/-    42.19)
 369 nsStr                                          20     4520   311956      226 ( 8173.30 +/-  3862.96)        0        0 (    0.00 +/-     0.00)
 375 nsStringKey                                   156    20904    10476      134 (  971.65 +/-   271.09)        0        0 (    0.00 +/-     0.00)
 378 nsSupportsArray                                40     1040     3826       26 (  914.67 +/-   386.64)    11006       27 (  873.29 +/-   390.87)
 380 nsSystemPrincipal                              52       52        1        1 (    1.00 +/-     0.00)     9313        1 (   18.30 +/-     5.51)
 391 nsThread                                       24       48        3        2 (    2.00 +/-     0.82)      395        7 (    9.93 +/-     0.93)
 392 nsThreadPool                                   48       48        1        1 (    1.00 +/-     0.00)        4        2 (    1.83 +/-     0.75)
 393 nsThreadPoolRunnable                           16       16        1        1 (    1.00 +/-     0.00)        3        1 (    1.80 +/-     0.84)
 404 nsUnicodeEncodeHelper                          12       12        1        1 (    1.00 +/-     0.00)        1        1 (    1.00 +/-     0.00)
 409 nsVoidArray                                     8      688     8348       86 ( 2360.87 +/-  1059.85)        0        0 (    0.00 +/-     0.00)
 415 nsXBLAttributeEntry                            24      432      427       18 (  217.91 +/-   120.89)      619       18 (  239.30 +/-   133.66)
 416 nsXBLBinding                                   44      176      236        4 (  118.97 +/-    67.59)     5752        4 (  138.50 +/-    70.94)
 421 nsXMLElement                                   64      512      414        8 (  204.96 +/-   114.51)    21768       10 (  334.57 +/-   175.92)
 424 nsXPCComponents                                48      144        9        3 (    5.20 +/-     2.37)       54        9 (   16.00 +/-     7.54)
 430 nsXPCWrappedJS                                 32     1504       50       47 (   26.77 +/-    15.09)      244       47 (   43.71 +/-    15.77)
 431 nsXPCWrappedJSClass                            44       44        4        1 (    2.29 +/-     1.11)      101       47 (   26.58 +/-    14.83)
 432 nsXPCWrappedNative                             48      144      113        3 (   49.70 +/-    25.53)     1250        3 (   71.37 +/-    28.13)
 433 nsXPCWrappedNativeClass                        48       48       28        1 (   13.09 +/-     6.87)      226        3 (   49.90 +/-    25.72)
 434 nsXPCWrappedNativeScope                        28       84        9        3 (    5.20 +/-     2.37)      122        3 (   47.23 +/-    26.40)
 437 nsXULAttribute                                 32     1248     3762       39 ( 1887.70 +/-  1075.64)     3762       39 ( 1887.70 +/-  1075.64)
 438 nsXULAttributes                                80     2320     1096       29 (  555.16 +/-   312.43)     1096       29 (  555.16 +/-   312.43)
 440 nsXULContentUtils                              12       12        1        1 (    1.00 +/-     0.00)       15        1 (    3.55 +/-     1.43)
 441 nsXULControllers                               20       40        3        2 (    2.00 +/-     0.82)      321        2 (    4.76 +/-     0.94)
 444 nsXULElement                                   84     2436     1805       29 (  827.57 +/-   420.24)   487475       49 ( 6055.95 +/-  3187.16)
 445 nsXULElement::Slots                            44     1276     1128       29 (  571.16 +/-   321.66)        0        0 (    0.00 +/-     0.00)
 448 nsXULPDGlobalObject                            32       32        5        1 (    2.78 +/-     1.39)       94        1 (    6.72 +/-     2.88)
 457 xptiInterfaceInfo                              36      144     1773        4 (  690.28 +/-   326.10)     2481        4 (  711.75 +/-   280.59)

Which objects leaked?

So, 4 out of 236 nsXBLBinding objects were leaked. Suppose (for demonstration purposes) that I think the nsXBLBinding might be the root leak. We want to know which ones, and whether they were leaked from nsCOMPtrs (which almost always means from a member variable of another leaked object).

> setenv XPCOM_MEM_LOG_CLASSES nsXBLBinding
> ./mozilla -editor

The very end of the output shows:

Serial Numbers of Leaked Objects:
279 (1 references; 0 from COMPtrs)
281 (1 references; 0 from COMPtrs)
280 (1 references; 0 from COMPtrs)
278 (1 references; 0 from COMPtrs)

The objects leaked were the 278th through 281st nsXBLBinding objects created (really, AddRefed). For each object leaked, there was one reference out of balance, and that reference was not held in an nsCOMPtr.

Finding the leaked reference (not an nsCOMPtr)

To find leaked references not leaked from nsCOMPtrs, use the refcount balancer to make a balance tree to find the 1 leaked reference on each of these objects:

> setenv XPCOM_MEM_LOG_OBJECTS 278-281
> setenv XPCOM_MEM_REFCNT_LOG ~/leaks/editor/nsXBLBinding.refcnt
> setenv XPCOM_MEM_COMPTR_LOG ~/leaks/editor/nsXBLBinding.comptr
> ./mozilla -editor

Then, in the directory with these logs, run the refcount balancer perl script on these logs:

> find-leakers.pl nsXBLBinding.refcnt
0x08A72EB0 (2) @ <nsXBLBinding>
0x08AD70B8 (4) @ <nsXBLBinding>
0x089F7CE0 (1) @ <nsXBLBinding>
0x08AD76E0 (3) @ <nsXBLBinding>
> make-tree.pl --ignore --object 0x089F7CE0 --comptr nsXBLBinding.comptr < nsXBLBinding.refcnt > nsXBLBinding.balance-ibic1

The --ignore-balance (or --ignore) option tells the refcount balancer not to print out subtrees that are balanced. The --comptr option tells it to subtract any reference counting caused by nsCOMPtrs. This option, when combined with --ignore-balance, usually causes subtrees to disappear, but occasionally it causes the nsCOMPtr information to be printed (as the negative of what really happened).

The output contains a refcount tree that has this at the tail:

1       nsCSSFrameConstructor::ConstructFrame(nsIPresShell *, nsIPresContext *, nsFrameConstructorState &, nsIContent *, nsIFrame *, nsFrameItems &)+0x00000202
  1       nsCSSFrameConstructor::ConstructFrameInternal(nsIPresShell *, nsIPresContext *, nsFrameConstructorState &, nsIContent *, nsIFrame *, nsIAtom *, int, nsIStyleContext *, nsFrameItems &, int)+0x00000101
    1       nsXBLService::LoadBindings(nsIContent *, nsString const &, int)+0x000003CF
    | 1       nsXBLService::GetBinding(nsCString const &, nsIXBLBinding **)+0x00000580
    |   1       NS_NewXBLBinding(nsIXBLBinding **)+0x00000050
    |     1       nsXBLBinding::AddRef(void)+0x0000006F
    -1      nsXBLService::LoadBindings(nsIContent *, nsString const &, int)+0x000003EE
    | -1      nsGetterAddRefs<nsIXBLBinding>::~nsGetterAddRefs(void)+0x0000005A
    1       nsXBLService::LoadBindings(nsIContent *, nsString const &, int)+0x000008D9
      1       nsBindingManager::SetBinding(nsIContent *, nsIXBLBinding *)+0x00000067
        1       nsSupportsHashtable::Put(nsHashKey *, nsISupports *, nsISupports **)+0x00000027
          1       unsigned int ns_if_addref<nsISupports *>(nsISupports *)+0x00000023
            1       nsXBLBinding::AddRef(void)+0x0000006F

This means that the leaked reference was through the nsSupportsHashtable of the nsBindingManager. Going back to the original leak logs, we see that there was one nsBindingManager leaked. So why did that leak?

Finding the reference leaked in an nsCOMPtr

So, repeat the same process to find out how the nsBindingManager leaked.

> setenv XPCOM_MEM_LOG_CLASSES nsBindingManager
> unsetenv XPCOM_MEM_REFCNT_LOG
> unsetenv XPCOM_MEM_COMPTR_LOG
> ./mozilla -editor

The very end of the output shows the following:

Serial Numbers of Leaked Objects:
14 (1 references; 1 from COMPtrs)

This means that the 14th object was leaked. There was one reference keeping it from being deleted, and that reference was held by an nsCOMPtr. So, there is no need to take a refcount log, only an nsCOMPtr log:

> setenv XPCOM_MEM_LOG_OBJECTS 14
> setenv XPCOM_MEM_COMPTR_LOG ~/leaks/editor/nsBindingManager.comptr
> ./mozilla -editor

After this is done, run the find-comptr-leakers.pl script on the output.

> find-comptr-leakers.pl nsBindingManager.comptr
Examining all objects
Object 14 held by 0x0895C408 is 1 out of balance.

Put into nsCOMPtr at:
nsCOMPtr<nsIBindingManager>::assign_assuming_AddRef(nsIBindingManager *)+0x00000043
nsCOMPtr<nsIBindingManager>::assign_from_helper(nsCOMPtr_helper const &, nsID const &)+0x00000052
nsCOMPtr<nsIBindingManager>::operator=(nsCOMPtr_helper const &)+0x00000027
nsDocument::GetBindingManager(nsIBindingManager **)+0x00000056
nsXBLService::LoadBindings(nsIContent *, nsString const &, int)+0x000000E6
nsCSSFrameConstructor::ConstructFrameInternal(nsIPresShell *, nsIPresContext *, nsFrameConstructorState &, nsIContent *, nsIFrame *, nsIAtom *, int, nsIStyleContext *, nsFrameItems &, int)+0x00000101
nsCSSFrameConstructor::ConstructFrame(nsIPresShell *, nsIPresContext *, nsFrameConstructorState &, nsIContent *, nsIFrame *, nsFrameItems &)+0x00000202
nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell *, nsIPresContext *, nsFrameConstructorState &, nsIContent *, nsIDocument *, nsIFrame *, nsFrameItems &)+0x00000314
nsCSSFrameConstructor::BuildGfxScrollFrame(nsIPresShell *, nsIPresContext *, nsFrameConstructorState &, nsIContent *, nsIDocument *, nsIFrame *, nsIStyleContext *, int, nsIFrame *&, nsFrameItems &)+0x000000B7
nsCSSFrameConstructor::BeginBuildingScrollFrame(nsIPresShell *, nsIPresContext *, nsFrameConstructorState &, nsIContent *, nsIStyleContext *, nsIFrame *, nsIAtom *, nsIDocument *, int, nsIFrame *&, nsCOMPtr<nsIStyleContext> &, nsIFrame *&)+0x000000A9
nsCSSFrameConstructor::ConstructRootFrame(nsIPresShell *, nsIPresContext *, nsIContent *, nsIFrame *&)+0x0000074D
StyleSetImpl::ConstructRootFrame(nsIPresContext *, nsIContent *, nsIFrame *&)+0x0000008F
PresShell::InitialReflow(int, int)+0x0000035F
HTMLContentSink::StartLayout(void)+0x00000353
HTMLContentSink::OpenBody(nsIParserNode const &)+0x000000EE
CNavDTD::OpenBody(nsIParserNode const *)+0x000000C4
CNavDTD::OpenContainer(nsIParserNode const *, nsHTMLTag, int, nsEntryStack *)+0x000002B8
CNavDTD::HandleDefaultStartToken(CToken *, nsHTMLTag, nsIParserNode *)+0x00000365
CNavDTD::HandleStartToken(CToken *)+0x0000039A
CNavDTD::HandleToken(CToken *, nsIParser *)+0x00000452
CNavDTD::BuildModel(nsIParser *, nsITokenizer *, nsITokenObserver *, nsIContentSink *)+0x00000291
nsParser::BuildModel(void)+0x0000009F
nsParser::ResumeParse(int, int)+0x00000139
nsParser::OnStopRequest(nsIChannel *, nsISupports *, unsigned int, unsigned short const *)+0x0000007C
nsDocumentOpenInfo::OnStopRequest(nsIChannel *, nsISupports *, unsigned int, unsigned short const *)+0x0000008B
nsStreamIOChannel::OnStopRequest(nsIChannel *, nsISupports *, unsigned int, unsigned short const *)+0x0000004A
nsOnStopRequestEvent::HandleEvent(void)+0x00000114
nsStreamListenerEvent::HandlePLEvent(PLEvent *)+0x0000005F
PL_HandleEvent+0x00000056
PL_ProcessPendingEvents+0x00000110
nsEventQueueImpl::ProcessPendingEvents(void)+0x00000071
nsAppShell::SetDispatchListener(nsDispatchListener *)+0x0000003C
keysym2ucs+0x0000015F
g_io_add_watch+0x000000AA
g_get_current_time+0x00000136
g_get_current_time+0x000006F1
g_main_run+0x00000081
gtk_main+0x000000B9
nsAppShell::Run(void)+0x00000052
nsAppShellService::Run(void)+0x0000003C
UNKNOWN 0x08053C55
UNKNOWN 0x0805433E
__libc_start_main+0x000000FF

So the nsBindingManager was leaked from a document, since nsDocument::GetBindingManager keeps a reference it acquires in a member nsCOMPtr.

JavaScript enters the picture

So, I do the same thing on the document:

> unsetenv XPCOM_MEM_COMPTR_LOG
> setenv XPCOM_MEM_LOG_CLASSES nsDocument
> ./mozilla -editor
Serial Numbers of Leaked Objects:
12 (1 references; 0 from COMPtrs)
> setenv XPCOM_MEM_LOG_OBJECTS 12
> setenv XPCOM_MEM_COMPTR_LOG ~/leaks/editor/nsDocument12.comptr
> setenv XPCOM_MEM_REFCNT_LOG ~/leaks/editor/nsDocument12.refcnt
> ./mozilla -editor
find-leakers.pl nsDocument12.refcnt 
> 0x0895C768 (1) @ <nsDocument>
> make-tree.pl --object 0x0895C768 --ignore --comptr nsDocument12.comptr < nsDocument12.refcnt > nsDocument12.balance-ibic

Close examination of the refcount log (or prior knowledge of this type of leak) reveals that the leaked reference is here:

1       NS_CreateScriptContext+0x0000124D
 1       GlobalWindowImpl::GetDocument(nsIDOMDocumentView **)+0x000000AF
  1       nsHTMLDocument::QueryInterface(nsID const &, void **)+0x00000186
   1       nsDocument::QueryInterface(nsID const &, void **)+0x000001E7
    1       nsHTMLDocument::AddRef(void)+0x0000001A
     1       nsDocument::AddRef(void)+0x00000072

This is the reference owned by the JS engine that is released when the object is garbage collected. Since there is no listing of js_GC at the bottom of the refcount balancer output, the document's script object was never garbage collected. (If js_GC is listed, it means that the object was released during garbage collection. One must look at the tree to see if it was the reference JS held to the object or if it was released through JS's reference to something else.)

The confusing part (this doesn't happen for most leaks)

There's something funny about this stack trace, because the Linux stack tracing code doesn't understand static functions. NS_CreateScriptContext doesn't call GlobalWindowImpl::GetDocument -- the NS_CreateScriptContext looks out of place. So I unsetenv all the logging variables and go into the debugger and break on GetDocument, and find it's called here:

#0  GlobalWindowImpl::GetDocument (this=0x40f81708, aDocumentView=0xbfffdde8) at /builds/dbaron/debug/mozilla/dom/src/base/nsGlobalWindow.cpp:2675
#1  0x403a6801 in GetWindowProperty (cx=0x40fd31c0, obj=0x80dca50, id=-73, vp=0xbfffe6b0) at /builds/dbaron/debug/mozilla/dom/src/base/nsJSWindow.cpp:568
#2  0x401e7677 in js_Interpret (cx=0x40fd31c0, result=0xbfffe794) at /builds/dbaron/debug/mozilla/js/src/jsinterp.c:2566

This is messy because it's called a lot. However, we also leak a GlobalWindowImpl, which is the document's global object, and that should be easier to debug. (It's what I would've looked at first if I weren't trying to demonstrate all these tools. If you leak a GlobalWindowImpl, find that leak first, because it generally means you leaked a JS GC root that could be holding on to an entire document.) So, run with XPCOM_MEM_LOG_CLASSES set to GlobalWindowImpl, giving the output:

1 (2 references; 1 from COMPtrs)
2 (1 references; 0 from COMPtrs)
3 (1 references; 0 from COMPtrs)

The nsCOMPtr log shows a leak

Examining all objects
Object 1 held by 0x08141584 is 1 out of balance.

Put into nsCOMPtr at:
UNKNOWN 0x08058483
nsCOMPtr<nsIDOMWindow>::assign_with_AddRef(nsISupports *)+0x00000038
nsCOMPtr<nsIDOMWindow>::operator=(nsIDOMWindow *)+0x0000001F
GlobalWindowImpl::SetOpenerWindow(nsIDOMWindow *)+0x00000021
GlobalWindowImpl::ReadyOpenedDocShellItem(nsIDocShellTreeItem *, nsIDOMWindow **)+0x0000011A
GlobalWindowImpl::OpenInternal(JSContext *, long *, unsigned int, int, nsIDOMWindow **)+0x00000E46
GlobalWindowImpl::OpenDialog(JSContext *, long *, unsigned int, nsIDOMWindow **)+0x00000031
UNKNOWN 0x08050A54
UNKNOWN 0x08051B40
UNKNOWN 0x08052212
UNKNOWN 0x080522DC
UNKNOWN 0x080539F3
UNKNOWN 0x0805436E
__libc_start_main+0x000000FF

and gdb shows this as:

#0  GlobalWindowImpl::SetOpenerWindow (this=0x41ecd2e8, aOpener=0x41e55adc) at /builds/dbaron/debug/mozilla/dom/src/base/nsGlobalWindow.cpp:358
#1  0x403c0252 in GlobalWindowImpl::ReadyOpenedDocShellItem (this=0x41e55ad8, aDocShellItem=0x40fefea4, aDOMWindow=0xbffff68c)
    at /builds/dbaron/debug/mozilla/dom/src/base/nsGlobalWindow.cpp:3250
#2  0x403bdc8e in GlobalWindowImpl::OpenInternal (this=0x41e55ad8, cx=0x41cfabb8, argv=0x41e75f88, argc=4, aDialog=1, aReturn=0xbffff68c)
    at /builds/dbaron/debug/mozilla/dom/src/base/nsGlobalWindow.cpp:2817
#3  0x403b820d in GlobalWindowImpl::OpenDialog (this=0x41e55ad8, cx=0x41cfabb8, argv=0x41e75f88, argc=4, aReturn=0xbffff68c)
    at /builds/dbaron/debug/mozilla/dom/src/base/nsGlobalWindow.cpp:1757
#4  0x8050a54 in OpenWindow (urlstr=0x41e01b68 "chrome://editor/content/editor.xul", args=0x41e8bd08)
    at /builds/dbaron/debug/mozilla/xpfe/bootstrap/nsAppRunner.cpp:253
#5  0x8051b40 in LaunchApplicationWithArgs (commandLineArg=0xbffffc38 "-editor", cmdLineArgs=0x8123210, 
    progID=0xbffff7a8 "component://netscape/commandlinehandler/general-startup-editor", height=-1, width=-1)
    at /builds/dbaron/debug/mozilla/xpfe/bootstrap/nsAppRunner.cpp:425
#6  0x8052212 in HandleArbitraryStartup (cmdLineArgs=0x8123210, prefs=0x80c7ff0, heedGeneralStartupPrefs=0)
    at /builds/dbaron/debug/mozilla/xpfe/bootstrap/nsAppRunner.cpp:572
#7  0x80522dc in DoCommandLines (cmdLine=0x8123210, heedGeneralStartupPrefs=0) at /builds/dbaron/debug/mozilla/xpfe/bootstrap/nsAppRunner.cpp:588
#8  0x80539f3 in main1 (argc=2, argv=0xbffffab4, nativeApp=0x0) at /builds/dbaron/debug/mozilla/xpfe/bootstrap/nsAppRunner.cpp:891
#9  0x805433e in main (argc=2, argv=0xbffffab4) at /builds/dbaron/debug/mozilla/xpfe/bootstrap/nsAppRunner.cpp:1099

This shows 1 leaked reference due to it or another leaked GlobalWindowImpl. I guess, from experience, that the more interesting question is where the second reference came from, since I suspect a leaked GC root. A refcount balance tree shows that this reference was created in NS_NewScriptWindow for JS to release when the object was garbage collected.

Debugging leaked JS roots

[ Information on how to get GC traces needs to be rewritten following the landing of bug 378261 and bug 378255 and a few patches that preceded them by a few weeks. That may just mean setting the XPC_SHUTDOWN_HEAP_DUMP environment variable to a file name. ]

The output when I run this shows that the object is not being released from JS because of a DocumentType object in the content model. The end of the output is:

080de9c8 object 0x81df3fc Window via Text(DocumentType).__proto__(DocumentType).__proto__(Node).__proto__(Object).__parent__(Window).document(HTMLDocument).location(Location).__proto__(Location).__parent__(Window).Location(Function).__parent__(Window).

The cause of the leak is that nsDocument::SetScriptGlobalObject is not properly unrooting script objects for content other than the root element (which includes the DocumentType). See bug 17390.

Conclusion

This was a difficult leak. For a run-of-the-mill missing release, you probably only need to use the first two tools described. However, I wanted to mention the JavaScript leaks because some of the largest leaks we see right now (July 2000) are coming from leaked GC roots.

These tools are the main method of attack (as far as I know) for finding leaked reference counts. The Boehm GC leak detector (if you have a Mac) can be very useful for finding which object is the root leak in a large ownership chain of leaked XPCOM objects. However, it still won't find the leaked reference. Other tools, such as the Boehm GC leak detector and Purify, are useful for finding leaks of non-XPCOM objects.


[ Up to Tools, Performance ]