Zombie compartments

This page tells you how to detect and avoid zombie compartments, which are a particular kind of memory leak. They can be caused by bugs in Firefox itself, or by bugs in Firefox add-ons.

Compartments

Firefox’s JavaScript memory is segregated into zones and compartments. Roughly speaking, all memory used by JavaScript code that is from a particular origin (i.e. website) goes into its own compartment. Firefox’s own JavaScript code also gets one or more compartments and so do add-on scripts. Multiple compartments can share a zone, where a zone keeps track of things that can easily and securely be shared between related compartments such as string data and type information.

Viewing live compartments

If you want to see a list of live compartments, type "about:memory" into the address bar and click on the Measure button. In the results, you'll find a js-main-runtime-compartments tree (whcih you may need to expand further) that lists all system (Firefox and add-ons) and user (website) compartments, These compartments are also listed in more detail in the Explicit Allocations section. That more fine-graned representation may look like this

β”‚  β”œβ”€β”€β”€28.45 MB (05.71%) -- top(https://www.google.de/, id=141)
β”‚  β”‚   β”œβ”€β”€13.66 MB (02.74%) -- active/window(https://www.google.de/)
β”‚  β”‚   β”‚  β”œβ”€β”€β”€7.83 MB (01.57%) -- js-compartment(https://www.google.de/)
β”‚  β”‚   β”‚  β”‚   β”œβ”€β”€3.56 MB (00.71%) -- objects
β”‚  β”‚   β”‚  β”‚   β”‚  β”œβ”€β”€3.04 MB (00.61%) ++ gc-heap
β”‚  β”‚   β”‚  β”‚   β”‚  β”œβ”€β”€0.51 MB (00.10%) ++ malloc-heap
β”‚  β”‚   β”‚  β”‚   β”‚  └──0.00 MB (00.00%) ── non-heap/code/asm.js
β”‚  β”‚   β”‚  β”‚   β”œβ”€β”€2.43 MB (00.49%) -- shapes
β”‚  β”‚   β”‚  β”‚   β”‚  β”œβ”€β”€1.47 MB (00.29%) ++ gc-heap
β”‚  β”‚   β”‚  β”‚   β”‚  └──0.96 MB (00.19%) ++ malloc-heap
β”‚  β”‚   β”‚  β”‚   β”œβ”€β”€1.03 MB (00.21%) -- scripts
β”‚  β”‚   β”‚  β”‚   β”‚  β”œβ”€β”€0.72 MB (00.14%) ── gc-heap [2]
β”‚  β”‚   β”‚  β”‚   β”‚  └──0.31 MB (00.06%) ── malloc-heap/data [2]
β”‚  β”‚   β”‚  β”‚   β”œβ”€β”€0.80 MB (00.16%) -- type-inference
β”‚  β”‚   β”‚  β”‚   β”‚  β”œβ”€β”€0.66 MB (00.13%) ── type-scripts [2]
β”‚  β”‚   β”‚  β”‚   β”‚  β”œβ”€β”€0.13 MB (00.03%) ── allocation-site-tables [2]
β”‚  β”‚   β”‚  β”‚   β”‚  └──0.02 MB (00.00%) ── object-type-tables [2]
β”‚  β”‚   β”‚  β”‚   └──0.01 MB (00.00%) -- sundries
β”‚  β”‚   β”‚  β”‚      β”œβ”€β”€0.01 MB (00.00%) ── malloc-heap [2]
β”‚  β”‚   β”‚  β”‚      └──0.00 MB (00.00%) ── gc-heap [2]
β”‚  β”‚   β”‚  └───5.83 MB (01.17%) -- (4 tiny)
β”‚  β”‚   β”‚      β”œβ”€β”€4.19 MB (00.84%) ++ layout
β”‚  β”‚   β”‚      β”œβ”€β”€1.03 MB (00.21%) ── style-sheets [2]
β”‚  β”‚   β”‚      β”œβ”€β”€0.60 MB (00.12%) ++ dom
β”‚  β”‚   β”‚      └──0.01 MB (00.00%) ── property-tables [2]
β”‚  β”‚   β”œβ”€β”€β”€8.86 MB (01.78%) -- cached/window(https://www.google.de/?gws_rd=ssl)
β”‚  β”‚   β”‚   β”œβ”€β”€4.23 MB (00.85%) -- layout
β”‚  β”‚   β”‚   β”‚  β”œβ”€β”€3.80 MB (00.76%) ── style-sets
β”‚  β”‚   β”‚   β”‚  β”œβ”€β”€0.29 MB (00.06%) ── pres-shell
β”‚  β”‚   β”‚   β”‚  β”œβ”€β”€0.05 MB (00.01%) ── rule-nodes
β”‚  β”‚   β”‚   β”‚  β”œβ”€β”€0.04 MB (00.01%) ── style-contexts
β”‚  β”‚   β”‚   β”‚  β”œβ”€β”€0.03 MB (00.01%) -- frames
β”‚  β”‚   β”‚   β”‚  β”‚  β”œβ”€β”€0.02 MB (00.00%) ── sundries
β”‚  β”‚   β”‚   β”‚  β”‚  └──0.01 MB (00.00%) ── nsBlockFrame
β”‚  β”‚   β”‚   β”‚  β”œβ”€β”€0.01 MB (00.00%) ── pres-contexts
β”‚  β”‚   β”‚   β”‚  β”œβ”€β”€0.01 MB (00.00%) ── line-boxes
β”‚  β”‚   β”‚   β”‚  └──0.00 MB (00.00%) ── text-runs
β”‚  β”‚   β”‚   β”œβ”€β”€3.78 MB (00.76%) ++ js-compartment(https://www.google.de/?gws_rd=ssl)
β”‚  β”‚   β”‚   β”œβ”€β”€0.51 MB (00.10%) ── style-sheets
β”‚  β”‚   β”‚   β”œβ”€β”€0.33 MB (00.07%) -- dom
β”‚  β”‚   β”‚   β”‚  β”œβ”€β”€0.17 MB (00.04%) ── text-nodes
β”‚  β”‚   β”‚   β”‚  β”œβ”€β”€0.13 MB (00.03%) ── element-nodes
β”‚  β”‚   β”‚   β”‚  β”œβ”€β”€0.02 MB (00.00%) ── other
β”‚  β”‚   β”‚   β”‚  β”œβ”€β”€0.01 MB (00.00%) ── orphan-nodes
β”‚  β”‚   β”‚   β”‚  └──0.00 MB (00.00%) ── event-targets
β”‚  β”‚   β”‚   └──0.00 MB (00.00%) ── property-tables
β”‚  β”‚   └───5.93 MB (01.19%) -- js-zone(0x13ffa0000)
β”‚  β”‚       β”œβ”€β”€1.92 MB (00.39%) ── unused-gc-things
β”‚  β”‚       β”œβ”€β”€1.28 MB (00.26%) -- lazy-scripts
β”‚  β”‚       β”‚  β”œβ”€β”€1.03 MB (00.21%) ── gc-heap
β”‚  β”‚       β”‚  └──0.25 MB (00.05%) ── malloc-heap
β”‚  β”‚       β”œβ”€β”€1.24 MB (00.25%) ── type-pool
β”‚  β”‚       β”œβ”€β”€1.07 MB (00.21%) -- type-objects
β”‚  β”‚       β”‚  β”œβ”€β”€1.04 MB (00.21%) ── gc-heap
β”‚  β”‚       β”‚  └──0.03 MB (00.01%) ── malloc-heap
β”‚  β”‚       β”œβ”€β”€0.23 MB (00.05%) ++ strings
β”‚  β”‚       └──0.18 MB (00.04%) ── gc-heap-arena-admin

The first line says that the window from www.google.de is taking up 28.45 MB and futher breaks it down into zones, compartments, DOM etc.

When are compartments created?

Any compartments with the following forms are created by Firefox for its own internal use, and can usually be ignored when looking for zombie compartments.

  • js-compartment([System Principal], 0x7f10f1250000)
  • compartment(atoms)
  • js-compartment(about:home)
  • js-compartment(about:blank)
  • compartment([System Principal], resource://gre/modules/addons/XPIProvider.jsm)

When looking at user compartments there are a couple of things to be aware of. First, many sites utilize scripts from other sites to provide advertisements, "like" and "+1" buttons, Twitter feeds, etc. So it's common for multiple compartments to be created for a single web page. For example, if I open www.techcrunch.com the following compartments are created.

(Some of those compartment URLs are long and have been truncated.)

Another thing to beware is each compartment is created for an origin (e.g. https://www.facebook.com/), but the name of the compartment includes all the trailing gunk (e.g. "plugins/like.php?..."). This trailing gunk can be misleading and you shouldn't pay too much attention to it. For example, if I open https://bugzilla.mozilla.org/show_bug.cgi?id=668871 in one tab, then compartment(https://bugzilla.mozilla.org/show_bug.cgi?id=668871) will show up in about:memory. If I then open https://bugzilla.mozilla.org/show_bug.cgi?id=700547 and close the first tab, the same compartment will continue to be used. So I'll end up with a compartment whose name doesn't match the only page open from that origin. This can be confusing at first, so be ready for it.

When are compartments destroyed?

Compartments are destroyed when they are garbage collected. This happens some time after the last reference to them disappears. This means there can be a delay between a page being closed and its compartments disappearing. Explicitly minimizing the memory (a couple of times), i.e. running the garbage collector, with the corresponding about:memory button will help.

Zombie compartments

Sometimes, due to bugs in Firefox, the Add-on SDK and/or add-ons, compartments are created that are never destroyed. These are a particular kind of memory leak, and they cause Firefox's memory usage to increase gradually over time, slowing it down and making it more likely to crash.

Reactive checking

If you look at about:memory and you see a compartment for www.foo.com, but you closed your last www.foo.com tab a while ago, there's a good chance you're seeing a zombie compartment. Follow these steps to make a more conclusive diagnosis.

  • Restart the browser.
  • Open the page that you think might cause a zombie compartment.
  • Open about:memory in another tab to confirm that the relevant compartment is present.
  • Close the first page.
  • Minimize memory usage and remeasure in about:memory. It might be worth refreshing multiple times just to be sure.
  • If the compartment is still present in about:memory, that's very suspicious. You could try waiting 20 minutes or so, then reload about:memory again. Some zombie compartments stick around for a limited time before disappearing, others are immortal, and it's useful to know which is which. If you see any `ghost-windows` (at the bottom of about:memory) that is also suspicious, as they are similar to zombie compartments.
  • Some zombie compartments are caused by add-ons. If you have add-ons enabled, please try to reproduce in safe mode, which disables them. If you can identify, by disabling them one at a time, a single add-on that is responsible, that is extremely helpful.
  • If you're confident you've found a zombie compartment, please file a bug that includes all the information you've gathered, add β€œ[MemShrink]” to its whiteboard, and mark it as blocking bug 668871. Attaching the full contents of about:memory?verbose is very helpful (and you can just cut and paste the page contents, there's no need to take a screenshot). See bug 669545 for an example. If the zombie compartment is caused by an add-on, please mark the bug as also blocking bug 700547.

It really is best to follow these instructions. In particular, if you have multiple tabs open it's easy to mis-identify whether a compartment should still be alive. If you only have about:memory open, things are much simpler.

Proactive checking of add-ons

It's not uncommon for add-ons to cause zombie compartments, see bug 700547 for examples. Follow these steps to do some basic checking of an add-on.

  • Create a new profile. Install and enable the add-on.
  • Restart the browser.
  • Browse one or more pages and do something that exercises the add-on. For example, for an add-on that remembers passwords, visit a site that requires a password; for an add-on that performs an operation involving a specific page element such as an image or a chunk of text, perform that operation. The more you exercise the add-on, the more thorough the testing will be, but in practice a lot of problems show up quickly.
  • Open about:memory and close all other pages.
  • Return to about:memory and minimize memory and remeasure, multiple times if necessary.
  • If only system compartments are present, and there are no ghost windows, congratulations! That's a good sign that the add-on doesn't cause zombie compartments. Otherwise, please file a bug (using the "Tech Evangelism" product and the "Add-ons" component), add "[MemShrink]" to its whiteboard, and mark it as blocking bug 668871 and bug 700547.
  • Restartless add-ons should also take special care that all their compartments get destroyed after disabling or uninstalling the add-on. (Please note that you may need to close the about:addons UI before changes are made).

Avoiding zombie compartments in add-ons

Once you know that an add-on causes a zombie compartment, the only way to identify the cause is to read the add-on's code. See Common causes of memory leaks in extensions for things to avoid.