# Bloatview

BloatView is a tool that shows information about cumulative memory usage
and leaks. If it finds leaks, you can use [refcount tracing and balancing](refcount_tracing_and_balancing.md)
to discover the root cause.

## How to build with BloatView

Build with `--enable-debug` or `--enable-logrefcnt`.

## How to run with BloatView

The are two environment variables that can be used.

    XPCOM_MEM_BLOAT_LOG

If set, this causes a *bloat log* to be printed on program exit, and
each time `nsTraceRefcnt::DumpStatistics` is called. This log contains
data on leaks and bloat (a.k.a. usage).

    XPCOM_MEM_LEAK_LOG

This is similar to `XPCOM_MEM_BLOAT_LOG`, but restricts the log to only
show data on leaks.

You can set these environment variables to any of the following values.

-   **1** - log to stdout.
-   **2** - log to stderr.
-   ***filename*** - write log to a file.

## Reading individual bloat logs

Full BloatView output contains 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, tab process 1862
        |<----------------Class--------------->|<-----Bytes------>|<----Objects---->|
        |                                      | Per-Inst   Leaked|   Total      Rem|
      0 |TOTAL                                 |       17     2484|253953338       38|
     17 |AsyncTransactionTrackersHolder        |       40       40|   10594        1|
     78 |CompositorChild                       |      472      472|       1        1|
     79 |CondVar                               |       24       48|    3086        2|
    279 |MessagePump                           |        8        8|      30        1|
    285 |Mutex                                 |       20       60|   89987        3|
    302 |PCompositorChild                      |      412      412|       1        1|
    308 |PImageBridgeChild                     |      416      416|       1        1|

The first line tells you the pid of the leaking process, along with the
type of process.

Here's how you interpret the columns.

-   The first, numerical column [is the index](https://searchfox.org/mozilla-central/source/xpcom/base/nsTraceRefcnt.cpp#365)
    of the leaking class.
-   **Class** - The name of the class in question (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 `nsString` you'll see the size of the header struct, not the
    size of the string contents!)
-   **Bytes Leaked** - The number of bytes per instance times the number
    of objects leaked: (Bytes Per-Inst) x (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!)

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
    [below](#how-to-instrument-your-objects-for-bloatview)
    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 not 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.

If you find leaks, you can use [refcount tracing and balancing](refcount_tracing_and_balancing.md)
to discover the root cause.

## Combining and sorting bloat logs

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

    perl tools/bloatview/bloattable.pl *log1* *log2* \... *logn* >
    *htmlfile*

This will produce an HTML file that contains a table similar to the
following (but with added JavaScript so you can sort the data by
column).

    Byte Bloats

       ---------- ---------------- --------------------------
       Name       File             Date
       blank      `blank.txt`      Tue Aug 29 14:17:40 2000
       mozilla    `mozilla.txt`    Tue Aug 29 14:18:42 2000
       yahoo      `yahoo.txt`      Tue Aug 29 14:19:32 2000
       netscape   `netscape.txt`   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.

       -------------------- --------------- ----------------- --------- --------- ---------- ---------- ------------------------------- --------- -------- ---------- ---------
       Class Name           Instance 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 (`blank.txt`), the difference
between the first log file and the second (`mozilla.txt`), the
difference between the second log file and the third (`yahoo.txt`), the
difference between the third log file and the fourth (`netscape.txt`),
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 tools/bloatview/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.

## BloatView and continuous integration

BloatView runs on debug builds for many of the test suites GNU has
running under continuous integration. If a new leak occurs, it will
trigger a test job failure.

BloatView's output file can also show you where the leaked objects are
allocated. To do so, the `XPCOM_MEM_LOG_CLASSES` environment variable
should be set to the name of the class from the BloatView table:

    XPCOM_MEM_LOG_CLASSES=MyClass mach mochitest [options]

Multiple class names can be specified by setting `XPCOM_MEM_LOG_CLASSES`
to a comma-separated list of names:

    XPCOM_MEM_LOG_CLASSES=MyClass,MyOtherClass,DeliberatelyLeakedClass mach mochitest [options]

Test harness scripts typically accept a `--setenv` option for specifying
environment variables, which may be more convenient in some cases:

    mach mochitest --setenv=XPCOM_MEM_LOG_CLASSES=MyClass [options]

For getting allocation stacks in automation, you can add the appropriate
`--setenv` options to the test configurations for the platforms you're
interested in. Those configurations are located in
`testing/mozharness/configs/`. The most likely configs you'll want to
modify are listed below:

-   Linux: `unittests/linux_unittest.py`
-   Mac: `unittests/mac_unittest.py`
-   Windows: `unittests/win_unittest.py`
-   Android: `android/androidarm.py`

## How to instrument your objects for BloatView

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);
      ...
    }
