Categories
add-ons Firefox Memory consumption MemShrink

MemShrink progress, week 40

The past week was fairly quiet for MemShrink.

Add-ons

Our testing of the top 100 installed add-ons is progressing slowly.  We need more help here.  Please join in if you are interested!

The Image Zoom and Baow add-ons were downgraded to “preliminarily reviewed” status because they cause zombie compartments, as per the new AMO policy.  The main effect of the downgrade is that they’ll show up lower in AMO search results.

Miscellaneous

I modified the storage of CSS properties and values to minimize waste caused by alignment.  On 64-bit platforms this reduced the size of a property/value pair from 24 bytes to 18 bytes, which saves about 0.5MB for an instance of Gmail.  (Gmail uses a lots of CSS!)  On 32-bit platforms the reduction is 1/3 the size, with a property/value pair dropping from 12 to 10 bytes.

Justin Lebar capped the amount of memory used for decoded images.  Decoded images in background tabs are currently discarded 20-40 seconds after they stop being visible in the foreground tab.  With Justin’s patch, there is now a second criterion:  if the decoded image cap is exceeded, decoded images in background tabs will be discarded until the cap is met.  (Decoded images in the foreground tab are never discarded, so it’s possible that all decoded images in background tabs are discarded and the cap is still exceeded.)  The cap defaults to 50MiB, but it can be changed in about:config with the image.mem.max_decoded_image_kb option.  The main effect of this change is that decoded images in background tabs will be discarded more quickly than they used to be in some circumstances.

Bug counts

This week’s bug counts:

  • P1: 22 (-2/+0)
  • P2: 129 (-6/+3)
  • P3: 92 (-3/+3)
  • Unprioritized: 0 (-0/+0)

That’s a net reduction of five bugs!  Furthermore, we only had five bugs to triage in today’s MemShrink meeting.  Good signs.

Categories
about:memory add-ons Memory consumption MemShrink

MemShrink progress, week 39

Add-ons

Versions of McAfee’s SiteAdvisor add-on prior to 3.4.1.195 have been soft-blocked due to an extreme memory leak.  This means that it will be disabled within Firefox, but users can re-enable it if they want to.  According to McAfee, most users should have been upgraded to 3.4.1.195 by now.  Unfortunately, version 3.4.1.195 still has some leaks, and progress on fixing them has stalled.  (If SiteAdvisor were an AMO add-on there’s a good chance it would have been downgraded to “preliminarily reviewed” by now.)

Leaks in the Lastpass, Fireshot, and Amabay add-ons have been fixed.

Miscellaneous

Two weeks ago I mentioned that the not-yet-public areweslimyet.com detected a large regression in memory consumption caused by incremental garbage collection.  Bill McCloskey adjusted the GC and CC heuristics in order to fix this.

Justin Lebar previously added monitoring of available physical and virtual memory monitoring on Windows;  if either goes below a threshold Firefox attempts to free up memory.  This week he added monitoring of available commit space.

When you switch to a new tab, decoded image data from the old tab is kept until a 20 second timer expires.  This is a good idea because you might switch back to the original tab quickly.  However, until this week, this don’t-discard-it-immediately behaviour was also used when a tab is closed!  Justin Lebar landed a patch which separates these two cases, i.e. it discards decoded image data immediately when a tab is closed.

I tweaked the presentation of the “window-objects” sub-tree in about:memory so that the memory used within each browser tab is more obvious.  This is another step towards true per-tab memory reporting.  Here’s an example for a tab in which I navigated first to valgrind.org and then to www.mozilla.org;  the URL within the “top(…)” line is the one shown in the address bar.

│   ├──1,933,824 B (02.68%) -- top(http://www.mozilla.org/, id=13)
│   │  ├──1,497,480 B (02.08%) -- active
│   │  │  ├──1,496,456 B (02.08%) -- window(http://www.mozilla.org/)
│   │  │  │  ├────876,912 B (01.22%) -- layout
│   │  │  │  │    ├──569,456 B (00.79%) ── arenas
│   │  │  │  │    ├──238,224 B (00.33%) ── style-sets
│   │  │  │  │    └───69,232 B (00.10%) ── text-runs
│   │  │  │  ├────316,216 B (00.44%) ── style-sheets
│   │  │  │  └────303,328 B (00.42%) ── dom [2]
│   │  │  └──────1,024 B (00.00%) -- window([system])
│   │  │         └──1,024 B (00.00%) ── dom
│   │  └────436,344 B (00.61%) -- cached
│   │       └──436,344 B (00.61%) -- window(http://valgrind.org/)
│   │          ├──312,496 B (00.43%) -- layout
│   │          │  ├──170,448 B (00.24%) ── style-sets
│   │          │  ├──125,040 B (00.17%) ── arenas
│   │          │  └───17,008 B (00.02%) ── text-runs
│   │          ├───76,600 B (00.11%) ── dom
│   │          └───47,248 B (00.07%) ── style-sheets

Bug counts

This week’s bug counts:

  • P1: 24 (-5/+0)
  • P2: 132 (-2/+3)
  • P3: 92 (-1/+6)
  • Unprioritized: 0 (-1/+0)

We only had to triage five bugs in today’s MemShrink meeting.  I don’t remember ever having such a small number.  As a result, we spent some time reviewing the P1 bugs, and decided that several could be downgraded to P2 because the situation had improved in some fashion.

Categories
MemShrink Uncategorized

Testing the top 100 add-ons for memory leaks

Yesterday I mentioned that the plan for testing the top 100 add-ons for memory leaks had hit a snag — our list is that of the top 100 installed add-ons, rather than the top 100 enabled add-ons, and the latter is what we really want.

However, after some thought, I’ve concluded that there is likely to be a lot of overlap between the two lists.  For example, I’d be surprised if any of the top 50 enabled add-ons are not in the top 100 installed add-ons list.  Furthermore, this kind of testing will never give perfect coverage anyway.

Therefore, there’s little point in delaying the testing while we wait for a better top 100 list.  If you are interested in helping, please jump in.  And if you contact me privately I’ll be able to suggest some add-ons that are towards the more popular end of the top 100 list.  Thanks, and apologies for any confusion I have caused!

Categories
about:memory add-ons Firefox Memory consumption MemShrink

MemShrink progress, week 38

After last week’s action, this week was quieter for MemShrink.

Add-ons

I mentioned last week the plan to test the top 100 add-ons for memory leaks.  Unfortunately we learned this week that the list I gathered is the top 100 installed add-ons, not the top 100 enabled add-ons.  It’s quite possible that a lot of installed “third-party” add-ons (those installed by a program outside of Firefox, such as anti-virus programs) are disabled, in which case this top 100 list won’t reflect actual usage.

As a result, the top 100 testing is on hold until we can resolve this issue.  Telemetry data may help, though that data might exhibit opt-in biases.  I’m also going to investigate the possibility of changing the daily ping to distinguish between enabled and disabled add-ons, which would give us fully representative data.

Landed patches

I merged the “dom+style” and “layout” trees in about:memory.  This is a step towards per-tab memory reporting.  It also probably breaks about:nosy 🙁

I also converted the DOM memory reporters to the new style, added measurement of URIs and links, and added measurement of the FramePropertyTable.  These changes reduced about:memory’s “heap-unclassified” by several MBs in common cases.

Bill McCloskey changed the GC marker stack so it shrinks periodically.  Previously it could grow from 256KB to over 2MB and would never be shrunk once that happened.

Bug counts

This week’s bug counts:

  • P1: 29 (-0/+1)
  • P2: 131 (-4/+6)
  • P3: 87 (-3/+7)
  • Unprioritized: 1 (-2/+1)
Categories
about:memory add-ons Firefox Garbage Collection Memory consumption MemShrink

MemShrink progress, week 37

It’s been a huge week for MemShrink.

Add-ons

I filed a bug on testing the top 100 add-ons for memory leaks.  The majority of these add-ons are not available on AMO and so are not subject to the leak checking done during AMO reviews.  The instructions and current test results are here.  Randell Jesup helped identify some some add-ons with unclear identities, and Nils Maier and Archaeopteryx have both tested several add-ons.  A month ago I said that add-ons that leak are the #1 problem for MemShrink, and this bug represents a huge step towards reducing that problem.  We’ll need lots of additional help to test this many add-ons, so please feel free to jump in!

As far as I know, comprehensive testing of the most popular add-ons has never been done before.  Although this testing is aimed at finding memory leaks, it’s quite possible it will uncover various other problems with add-ons.  Indeed, it’s clear just from looking at the list that quite a few of the non-AMO add-ons are of dubious merit, and this has stimulated some interesting discussion on dev-platform about third-party add-ons, i.e. those that are installed into Firefox by an external program.

The following add-ons had leaks fixed or mostly fixed by their authors: McAfee Site Advisor, Ghostery, Spool, Screengrab (fix version), Roboform, UF Comment Board ToolsGeenstijl, Long URL Please, HTML Desktop Notifications.

Nils Maier greatly improved the documentation on common causes of memory leaks in add-ons.  This was a MemShrink:P1 bug.  That doesn’t mean the document can’t be improved further, however;  it’s a wiki so please continue to add to it if you can.

Regression testing

John Schoenick’s excellent areweslimyet.com is getting close to being ready for a public unveiling.  The site is currently live but password-protected, simply to prevent large numbers of people accessing it before it’s ready.  (If you want a sneak peek, contact me for the password.)  More importantly, it identified a large regression in memory consumption caused by the landing of the JS engine’s incremental garbage collector on February 19, which Bill McCloskey is investigating.

Tim Taubert improved Firefox’s regression testing to ensure that no new DocShell and DOMWindow leaks are introduced.  This was a MemShrink:P1 bug because these leaks are quite easy to introduce.  Tim wrote some more about this change here.

Cycle collector

Jan Honza Odvarko’s about:ccdump add-on made it onto AMO this week.  Jan has been using this to hunt down some tricky leaks in Firebug.

Marco Bonardo fixed a leak in PlacesUtils.removeLazyBookmarkObserver() that I won’t pretend to understand, but which was a MemShrink:P1.  Marco also fixed a leak that occurred after bookmarking a page, closing the window, and opening a new window.

Olli Pettay fixed an equally impenetrable (to me) leak involving nsFormFillController::mFocusedInput.

Kyle Huey fixed a leak in the About Firefox dialog.

Andrew McCreight added additional information to cycle collector’s error console logging, which helps with identifying and debugging cycle collector problems.

Miscellaneous

Jason Duell fixed an obscure leak involve web sockets.

Bill McCloskey fixed a minor JS engine leak.

I added a new memory reporter called “js/runtime/gc-marker”.  It starts out at 256KB and I saw it reach 2.8MB when running MemBench.  I also converted the existing source image reporters to the new style, which seems to haved fixed some bogus results in about:memory as a side-effect.

Quote of the week

Adam Overa of Tom’s Hardware did another browser Grand Prix.  Devin Coldewey used the results from the Grand Prix to conclude that Firefox and Chrome are both great, and which you prefer basically comes down to a matter of taste.  While that is an interesting conclusion, what caught my eye was this comment, by Balaji Viswanathan:

I guess the title could have been “All browsers suck equally bad now”. Firefox and Chrome have grown to become more resources hogs – closer to IE. These days I shudder to fire up the firefox as the memory leaks are terrible. Two hours of Firefox with a Facebook tab is enough to gobble up 25% of my memory. With Chrome, I would have 20 rendering processes showing up when I would have just 3 tabs open.

In the first 2 years of Chrome I had probably 2 or 3 crashes. These days, it crashes every week or so. I long for the 2006 era Firefox – clean, simple and lean. Its been a long time since I have used IE actively and with Safari lesser said the better. For the developers, we have to deal with the ultra slow update cycles of IE and ultraspeed update cycles of Chrome. In short, we are getting worse and worse in the browser arena. The market is ripe for a breakthrough.

“2006 era Firefox” would have been Firefox 1.5 or Firefox 2.  Balaji may think he’s nostalgic for browsers of that era, but really he’s nostalgic for the web of that era, which was massively simpler than the web of today.  If Balaji tried Firefox 1.5 or Firefox 2 today — with no HTML5 support, no JavaScript JIT and no hardware acceleration — today, I’m sure he’d quickly decide that 2012-era browsers aren’t so bad after all.  I guess the interesting question is this: why do people blame browsers instead of websites for high resource consumption?

Bug counts

This week’s bug counts:

  • P1: 28 (-5/+5)
  • P2: 129 (-12/+7)
  • P3: 83 (-8/+12)
  • Unprioritized: 2 (-2/+2)

That’s a net reduction of one bug.  But more importantly, there is lots of movement, which is great!  It means that problems are being identified and fixed.

(Finally, commenters please note that I’ve turned on the WP-reCAPTCHA plug-in, and this the first post I’ve written since doing so.  In my testing it’s worked fairly well.  Hopefully it won’t cause problems.)

Categories
about:compartments about:memory add-ons compartments Firefox Memory consumption MemShrink

MemShrink progress, week 36

Lots of activity this week.

Leaky add-ons

I created a new devmo wiki page documenting common causes of memory leaks in add-ons.  I based this on a lovely selection of examples provided by Nils Maier.  Unfortunately, I know almost nothing about writing add-ons and so I’m not happy with the current state of the documentation.  I’ve taken it as far as I can, but it very likely has errors, leaves out important cases, conflates distinct concepts, and generally is not as good as it should be.  This documentation is really important — we have good tools for identifying when add-on leaks occur but we don’t yet have good tools for identifying their causes.  Until we have those tools, documentation is the only way we can help add-on authors fix leaks.  If someone who knows more about add-ons is willing to help please contact me!

Alexandre Poirot fixed a leak in the Add-on SDK that was causing zombie compartments when certain add-ons were disabled.  This also fixed bug 725603 and probably fixes some zombie compartments reported in some other add-ons (e.g. MemChaser).

Jan fixed several leaks in the Galaxytoolbar add-on.  The new version is 2.6.12.

A small number of add-ons have been found that disable Firefox’s XUL cache.  This is a recipe for disastrous performance, and so Matt Basta updated the AMO add-on validator to detect this.

Tools

I landed support for a new page called about:compartments. The exposure of zombie compartments in about:memory has become an extremely powerful leak detection tool.  But using about:memory to find zombies is non-trivial — there are multiple steps and ways to get it wrong.  The motivation for about:compartments is to make the detection of zombie compartments as simple as possible.  Here’s a screenshot:

about:compartments screenshot

Some things to note:

  • It only shows compartments, and all of them.
  • User compartments from web content (usually the interesting ones) are listed separately from system compartments.
  • The garbage and cycle collectors are automatically run when the page is loaded, ensuring that dead compartments aren’t listed.
  • The “More verbose” link at the bottom just causes the truncated URLs to be shown in full.
  • about:compartments shares a lot of code with about:memory.
  • I updated the documentation on zombie compartments accordingly.

Olli Pettay created about:cc, an add-on that can detect various kinds of document leaks relating to cycle collection.  Olli has already found several leaks with this tool.  Jan Honza Odvarko has written about:ccdump, a similar but prettier add-on.  I’m not certain but I think Olli and Jan are now co-ordinating their efforts.

I mentioned Mozilla QA’s MemChaser add-on a few weeks ago.  It lets you track memory usage and GC/CC activity easily via the add-on bar, and also allows logging of memory-related activities.  It’s now available on AMO, which guarantees you’ll receive updates as they’re released.

Jesse Ruderman tweaked his DOM fuzzer and found several new small leaks relating to nsITimers.  Jesse also modified about:memory so that it produces assertions that his fuzzer will catch.  This means that his fuzzer will detect if any memory reporters produce bogus values.

Miscellaneous

Kyle Huey fixed a zombie compartment that occurred when searching within pages with onclick handlers, which is a pretty common operation.

Jeff Muizelaar fixed a huge Mac-only leak relating to text rendering.  This was a recent regression that isn’t present in any released version of Firefox.

Josh Aas fixed a bug in cookie clearing — prior to Josh’s fix, if you cleared all cookies, Firefox would launch an instance of the plugin-container process for every plug-in installed, which could cause freezes and memory spikes.

Andrew Quartey updated the WebGL memory reporters to the new style.

Bug counts

This week’s bug counts:

  • P1: 28 (-1/+3)
  • P2: 134 (-6/+9)
  • P3: 79 (-8/+11)
  • Unprioritized: 2 (-1/+2)

Lots of movement there:  plenty of bugs fixed, but even more new ones.  Roughly 20 of the new ones fell into the following three categories.

  • Zombie compartments found in AMO add-ons by Kris Maglione and Andreas Wagner.
  • Leaks found by Olli Pettay’s new about:cc tool, mentioned above.
  • Leaks found by Jesse Ruderman’s tweaked DOM fuzzer, mentioned above.

This is a good thing!  It shows that new policies and tools are exposing existing problems.  I expect this higher level of new bug filing will continue for a couple of weeks.

Categories
add-ons Firefox Memory consumption MemShrink

McAfee is killing us

A reader named AC commented on last week’s MemShrink report that Firefox was consuming lots of memory on his girlfriend’s computer (emphasis added by me):

I am currently on my girlfriends laptop round at her house and I am surfing the net using Firefox 10.0.1. The memory usage is terrible. It may be because of the two McAfee add-ons that she has, I don’t know, but I can see now first hand how some Firefox users are having an amazing experience and others are still lagging behind. The memory usage as opposed to being 200,000-230,000kb as it would be on my laptop with 11 beta 2 is about 350,000kb or more. That said, there is no loss of performance and that is what matters most. I am not looking for answers or solutions, merely saying that the same or very similar software used on one computer can perform completely differently on another and now I appreciate that even more having witnessed it for myself.

I asked him to try turning off the McAfee add-ons, which he kindly did.  The result (emphasis again added by me):

I did some very very rudimentary tests earlier at my girlfriends house on her laptop and here is what I found.

With the two McAfee add-ons running everything was fine until I got to about 8 tabs and then the memory began to increase. Then it just climbed up to about 450,000 kb. If I was running the same tab load on my latop, I would expect just over half that amount of memory to be reported in task manager.

I have to say that there was no loss of performance, but the amount of memory being used was very high for the tab load.

The first tab that I had open was google.co.uk. I right clicked on that tab and hit “Close Other Tabs”. The memory stayed at 418,000 kb and that was it. It stayed at that level for about 10 minutes whilst I went and did other stuff. It wasn’t going up or down. 400MB with just Google UK open and nothing else. It’s diabolical.

So I then disabled the 2 McAfee add-ons and every went back to normal. I used a heavy tab load than before. I opened more tabs with more complex content. I must have had about 15 tabs open and the memory use peaked at 386,000 kb.

Then I logged out of Facebook and Hotmail, without closing any tabs, and within 10 seconds the memory had dropped to 330,000 kb.

Then I closed all but 3 tabs and within 30 seconds the memory was about 180,000.

Then I closed all but one tab and the memory settled at just under 100,000 kb. Back to normal. Exactly how I would expect Firefox 10.0.1 to perform.

The extensions in question were McAfee ScriptScan for Firefox 14.4.1 and McAfee Site Advisor 3.4.1

I didn’t have time to test them individually as things got hectic after that, but as you say Nicholas, the seemingly innocent extensions were ruining the memory performance of a perfectly good browser.

I could still load pages etc and navigate around as fast, but the numbers on task manager were sky high.

Firefox has a reputation in particular for not releasing memory when tabs are closed.  75% of installed add-ons are not hosted on AMO, and thus are out of Mozilla’s control.  This is killing us.  Bug 720856 is my best suggestion for dealing with badly written add-ons such as these ones, but even it feels like weak tea when the problem is so large.

Categories
about:memory add-ons Firefox Memory consumption MemShrink

MemShrink progress, week 35

Add-ons

Zombie compartments were fixed in the following add-ons:  Customize Your Web (fixed by Rudolf Noe), GridTube (fixed by Costas B.), Do Not Track Plus (fixed by kiran).

Marco Bonardo changed the Places JS services in a way that prevents certain kinds of SQLite connection leaks.  As far as I can tell, this fixes leaks in the Delicious Bookmarks and CyberSearch add-ons.

Finally, Alexandre Poirot fixed a bug in the Add-on SDK that was causing zombie jetpack compartments in some cases when add-ons were disabled.

Memory Reporting

Hugh Nougher added a memory reporter for GPU memory on Windows 7 and Vista.  See the “gpu-committed”, “gpu-dedicated” and “gpu-shared” entries in about:memory’s “Other Measurements” list.

I reduced the amount of memory allocated when generating about:memory by about 35%.

Miscellaneous

Josh Aas implemented unloading for out-of-process plug-ins.  If one is unused for 3 minutes it will be unloaded.

Andrew McCreight improved cycle collector dumping, which is useful in certain debugging cases.

Quote of the week

LifeHacker did some browser performance tests.  Firefox 10 handily won the memory usage test, which involved loading sites in 9 tabs and then measuring.  I personally think this is a pretty meaningless test, but I won’t complain about the good press.

As usual, the comments on the article featured a lot of debate about  whether Firefox is a memory hog or not.  One comment particular caught my attention:

They hardly used to be myths. I saw several times when old FF2x would be taking up over 1.4GB of RAM with just half a dozen tabs open.

Firefox 2 was released in October 2006, and superseded by Firefox 3 in June 2008.  Bad reputations are really difficult to shake.

Bug counts

This week’s bug counts:

  • P1: 26 (-0/+4)
  • P2: 131 (-6/+3)
  • P3: 76 (-2/+3)
  • Unprioritized: 1 (-2/+1)
Categories
about:memory add-ons Firefox Memory consumption MemShrink

MemShrink progress, week 34

Add-ons

The AMO add-on review checklist was amended a couple of weeks ago to include checks for zombie compartments.  This change is bearing fruit:  Andreas Wagner and Kris Maglione have found more than 10 submitted add-ons that have leaks.  See here, here, here, here, here.  With the experience they are gaining, we should be able to greatly improve the documentation on common causes of leaks.

In less positive news, two leaks were found in the add-on SDK.  Fortunately the SDK team has proven to be effective at fixing identified leaks quickly in the past, hopefully they’ll do so again!

Finally, Jason Tackaberry fixed a zombie compartment in NoSquint 2.1.2.  The fix is in the latest version (2.1.5).

about:nosy

Andrew Sutherland wrote a extension called about:nosy which is like about:memory on steroids.  It’s oriented around hiding many of the details and instead assigning blame for memory allocations to particular tabs (and similar things).  It also features graphs showing how the memory consumption of each tracked entity changes over time;  this latter feature is quite memory and CPU-intensive, however.  If you are running a recent Nightly build of Firefox, download about:nosy here and you won’t even have to restart Firefox to see it, just type “about:nosy” into the address bar.

Forthcoming changes will make about:memory more like about:nosy, by measuring more things on a per-tab basis.  And for a long time I have had a vague plan that one day someone who knows about UX will write a user-friendly alternative to about:memory that focuses just on per-tab memory consumption, and about:nosy is a good indicator of what that might look like.

Miscellaneous

Saptarshi Guha from the metrics team did an analysis of the physical memory consumption of Firefox 10, 11 and 12, based on telemetry data.  The post is heavy going for those who aren’t experts at statistics and R, but the two main conclusions of interest are (a) that add-ons significantly increase resident memory consumption, and (b) Firefox 12 is consuming more resident memory than Firefox 11.  This latter fact matches something we’d seen in today’s MemShrink meeting when looking at data from John Schoenick’s in-development version of areweslimyet.com — something in early January caused a significant memory consumption regression.  John is working on narrowing down which change caused this.

Gian-Carlo Pascutto overhauled the safe browsing implementation.  I don’t claim to understand this change at all, but I think it reduces memory consumption when the database is updated.  Better explanations from those who understand this change are welcome!

I reduced the amount of memory allocated when generating about:memory by roughly 30%.

I wrote a detailed discussion of the benefits of reducing memory consumption.

Bug Counts

Here are this week’s bug counts.

  • P1: 22 (-0/+0)
  • P2: 134 (-4/+8)
  • P3: 75 (-3/+4)
  • Unprioritized: 2 (-2/+1)
Categories
Firefox Memory consumption MemShrink

The benefits of reducing memory consumption

TL;DR: Any single change that reduces Firefox’s memory consumption can affect Firefox’s speed, stability and reputation in a variety of ways, some of which are non-obvious.  Some examples illustrate this.

The MemShrink wiki page starts with the following text.

MemShrink is a project that aims to reduce Firefox’s memory consumption. There are three potential benefits.  Speed. […] Stability. […] Reputation.”

I want to dig more deeply into these benefits and the question of what it means to “reduce Firefox’s memory consumption”, because there are some subtleties involved.  In what follows I will use the term “MemShrink optimization” to refer to any change that reduces Firefox’s memory consumption.

Speed

People tend to associate low memory consumption with speed.  However, time/space trade-offs abound in programming, and an explicit goal of MemShrink is to not slow Firefox down — the wiki page says:

Changes that reduce memory consumption but make Firefox slower are not desirable.

There are several ways that MemShrink optimizations can improve performance.

Paging

The case that people probably think of first is paging.  If physical memory fills up and the machine needs to start paging, i.e. evicting virtual memory pages to disk space, it can be catastrophic for performance.  This is because disk accesses are many thousands of times slower than RAM accesses.

However, some MemShrink optimizations are far more likely to affect paging than others.  The key idea here is that of the working set size — what’s important is not the total amount of physical or virtual memory being used, but the fraction of that memory that is touched frequently.  For example, consider two programs that allocate and use a 1GB array.  The first one touches pages within the array at random.  The second one touches every page once and then touches the first page many times.  The second program will obviously page much less than the first if the system’s physical memory fills up.

The consequence of this is that a change that reduces the size of data structures that are accessed frequently is much more likely to reduce paging than a change that reduces the size of data structures that are accessed rarely.  Note that this is counter-intuitive!  It’s natural to want to optimize data structures that are wasteful of space, but “wasteful of space” often means “hardly touched” and so such optimizations don’t have much effect on paging.

Measuring the working set size of a complex program like a web browser is actually rather difficult, which means that gauging the impact of a change on paging is also difficult.  Julian Seward’s virtual memory profiler offers one possible way.  Another complication is that results vary greatly between machines.  If you are running Firefox on a machine with 16GB of RAM, it’s likely that no change will affect paging, because Firefox is probably never paging in the first place.  If you are on a netbook with 1GB of RAM, the story is obviously different.  Also, the effects can vary between different operating systems.

Cache pressure

Some MemShrink optimizations can also reduce cache pressure.  For example, a change that makes a struct smaller would allow more of them to fit into a cache line.  Like paging, these effects are very difficult to quantify, and changes that affect hot structures are more likely to reduce cache pressure significantly and improve performance.

Structure traversals

Sometimes large data structures must be traversed, and reducing the number of elements in the data structure can reduce that traversal time.  The obvious case for Firefox is the JavaScript heap — the garbage collector and cycle collector frequently traverse it, and so any change that causes dead objects to accumulate more slowly will reduce their traversal times.

Only a small fraction of MemShrink optimizations will speed up structure traversals.

Stability

If Firefox (or any program) uses too much memory, it can lead to aborts and crashes.  These are sometimes called “OOMs” (out of memory). There are two main kinds of OOM:  those involving virtual memory, and those involving physical memory.

Virtual OOMs

A “virtual OOM” occurs when the virtual address space fills up and Firefox simply cannot refer to any more memory.  This is mostly a problem on Windows, where Firefox is distributed as a 32-bit application, and so it can only address 2GB or 4GB of memory (the addressable amount depends on the OS configuration).  This is true even if you have more than 4GB of RAM.  In contrast, Mac OS X and Linux builds of Firefox are 64-bit and so virtual memory exhaustion is essentially impossible because the address space is massively larger.

(I don’t want to get distracted by the question of why Firefox is a 32-bit application on Windows.  I’ll just mention that (a) many Windows users are still running 32-bit versions of Windows that cannot run 64-bit applications, and (b) Mozilla does 64-bit Windows builds for testing purposes.  Detailed discussions of the pros and cons of 64-bit builds can be read here and here.)

The vast majority of MemShrink optimizations will reduce the amount of virtual memory consumed.  (The only counter-examples I can think of involve deliberately evicting pages from physical memory.  E.g. see the example of the GC decommitting change discussed below.)  And any such change will obviously reduce the number of virtual OOMs.  Furthermore, the effect of any reduction is obvious and straightforward — a change that reduces the virtual memory consumption by 100MB on a particular machine and workload is twice as good as one that reduces it by 50MB.  Of course, any improvement will only be noticed by those who experience virtual OOMs, which typically is people who have 100s of tabs open at once.  (It may come as a surprise, but some people have that many tabs open regularly.)

Physical OOMs

A “physical OOM” occurs when physical memory (and any additional backing storage such as swap space on disk) fills up.  This is mostly a problem on low-end devices such as smartphones and netbooks, which typically have small amounts of RAM and may not have any swap space.

The situation for physical memory is similar to that for virtual memory:  almost any MemShrink optimization will reduce Firefox’s physical memory consumption.  (One exception is that it’s possible for a memory allocation to consume virtual memory but not physical memory if it’s never accessed;  more about this in the examples section below.)  And any reduction in physical memory consumption will in turn reduce the number of physical OOMs.  Finally, the effects are again obvious and straightforward — a 100MB reduction is twice as good as a 50MB reduction.

Reputation

Finally, we have reputation.  The obvious effect here is that if MemShrink optimizations cause Firefox to become faster and more stable over time, people’s opinion of Firefox will rise, either because their own experience improves, or they hear that other people’s experience improves.

But I want to highlight a less obvious aspect of reputation.  People often gauge Firefox’s memory consumption by looking at a utility such as the Task Manager (on Windows) or ‘top’ (on Mac/Linux).  Interpreting the numbers from these utilities is rather difficult — there are multiple metrics and all sorts of subtleties involved.  (See this Stack Overflow post for evidence of the complexities and how easy it is to get things wrong.)  In fact, in my opinion, the subtleties are so great that people should almost never look at these numbers and instead focus on metrics that are influenced by memory consumption but which they can observe directly as users, i.e. speed and crash rate… but that’s a discussion for another time.

Nonetheless, a non-trivial number of people judge Firefox on this metric.  Imagine a change that caused Firefox’s numbers in these utilities to drop but had no other observable effect.  (Such a change may be impossible in practice, but that doesn’t matter in this thought experiment.)  One thing that has consistently surprised me is that some people view memory consumption as something approaching a moral issue:  low memory consumption is virtuous and high memory consumption is sinful.  As a result, this hypothetical change would improve Firefox’s reputation, rightly or wrongly, for the better.

Let’s call this aspect of Firefox’s reputation the “reputation-by-measurement”.  I suspect the most important metric for reputation-by-measurement is the “private bytes” reported by the Windows Task Manager, because that’s what people seem to most often look at.  Private bytes measures the virtual memory of a process that is not shared with any other process.  It’s my educated guess that in Firefox’s case that the amount of shared memory isn’t that high, and so the situation is similar to virtual OOMs above — just about any change that reduces the amount of virtual memory will reduce the private bytes by the same amount, and in terms of reputation-by-measurement, a 100MB reduction is twice as good as a 50MB reduction.

Examples

Some examples help bring this discussion together.  Consider bug 609905, which removed a 512KB block of memory that was found to be allocated but never accessed.  (This occurred because some code that used that block was removed but the allocation wasn’t removed at the same time.)  What were the benefits of this change?

  • The 512KB never would have been in the working set, so performance would not have been affected.
  • Virtual memory consumption would have dropped by 512KB, slightly reducing the likelihood of virtual OOMs.
  • Physical memory consumption probably didn’t change — because the block was never accessed, it probably never made it into physical memory.
  • Private bytes would have dropped by 512KB, slightly improving reputation-by-measurement.

Now consider bug 670596, which made the JavaScript garbage collector decommit (i.e. remove from physical memory and backing storage) 1MB heap chunks that are unused.  What were the benefits of this change?

  • Performance may have improved slightly due to reduced paging, on machines where paging happens.  Those chunks are clearly not in the working set when they are decommitted, but if paging occurs, the pre-emptive removal of some pages from physical memory may prevent the OS from having to evict some other pages, some of which might have been in the working set.
  • Virtual memory consumption would not have changed at all, because decommitted memory still takes up address space.
  • Physical memory consumption would have dropped by the full decommit amount — 10s or even 100s of MBs in many cases when decommitting is triggered — significantly reducing the likelihood of physical OOMs.
  • Private bytes would not have changed, leaving reputation-by-measurement unaffected. [Update: Justin Lebar queried this. This page indicates that decommitting memory does reduce private bytes, which means that this change would have improved reputation-by-measurement.]

Another interesting one is bug 676457.  It fixed a problem where PLArenaPool was requesting lots of allocations of ~4,128 bytes.  jemalloc rounded these requests up to 8,192 bytes, so almost 50% of each 8,192 byte block was wasted, and there could be many of these blocks.  The patch fixed this by reducing the requests to 4,096 bytes which is a power-of-two and not rounded up (and also usually the size of an OS virtual memory page).  What were the benefits of this change?

  • Performance may have improved due to less paging, because the working set size may have dropped.  The size of the effect depends how often the final 32 used bytes of each chunk — those that spilled onto a second page — are accessed.  For at least some of the blocks those 32 bytes would never be touched.
  • Virtual memory consumption dropped significantly, reducing the likelihood of virtual OOMs.
  • Physical memory consumption may have dropped, but it’s not clear by how much.  In cases where the extra 32 bytes are never accessed, the second page might not have ever taken up physical memory.
  • Private bytes would have dropped by the same amount as virtual memory, improving reputation-by-measurement.

Finally, let’s think about a compacting, generational garbage collector, something that is being worked on by the JS team at the moment.

  • Performance improves for three reasons.  First, paging is reduced because of the generational behaviour:  much of the JS engine activity occurs in the nursery, which is small;  in other words, the memory activity is concentrated within a smaller part of the working set.  Second, paging is further reduced because of the compaction: this reduces fragmentation within pages in the tenured heap, reducing the total working set size.  Third, the tenured heap grows more slowly because of the generational behaviour: many objects are collected earlier (in the nursery) than they would be with a non-generational collector, which means that structure traversals done by the garbage collector (during full-heap collections) and cycle collector are faster.
  • Virtual memory consumption drops in two ways.  First, the compaction minimizes waste due to fragmentation.  Second, the heap grows more slowly.
  • Physical memory consumption drops for the same two reasons.
  • Private bytes also drops for the same two reasons.

A virtuous change indeed.

Conclusion

Reducing Firefox’s memory consumption is a good thing, and it has the following benefits.

  • It can improve speed, due to less paging, fewer cache misses, and faster structure traversals.  These changes are likely to be noticed more by users on lower-end machines.
  • It improves stability by reducing virtual OOM aborts, which mostly helps heavy tab users on Windows.  It also improves stability by reducing physical OOM aborts, which mostly affects heavy-ish tab users on small devices like smartphones and netbooks.
  • It improves reputation among those whose browsing experience is improved by the above changes, and also among users who make judgments according to memory measurements with utilities like the Windows Task Manager.

Furthermore, when discussing MemShrink optimizations, it’s a good idea to describe improvements in these terms.  For example, instead of saying “this change reduces memory consumption”, one could say “this change reduces physical and virtual memory consumption and may reduce paging”.  I will endeavour to do this myself from now on.