This was the final week of development for Firefox 7, and lots of exciting MemShrink stuff happened.
Per-compartment memory reporters
I landed per-compartment memory reporters, using the new memory multi-reporter interface. I’ve written previously about per-compartment reporters; the number of things measured has increased since then, and each compartment now looks like this:
One nice thing about this feature is that it gives technically-oriented users a way to tell which web sites are causing high memory usage. This may help with perception, too; people might think “geez, Facebook is using a lot of memory” instead of “geez, Firefox is using a lot of memory”.
Another nice thing is that it can help find leaks. If you close all your tabs and some compartments are still around, that’s a leak, right? Actually, it’s more complicated than that: compartments are destroyed by the garbage collector, so there can be a delay. But there are buttons at the bottom of about:memory which force GC to occur, so if you press them and some compartments are still around, that’s a leak right? Well, it appears that sites that use timers can stick around while the timers are still live. For example, TBPL appears to have a refresh timer that is 2 or 3 minutes long, so it’s compartment stays alive for that long after the page is closed. (Actually, it’s not entirely clear if or why that should happen.) However, once you’ve accounted for these complications, any remaining compartments are likely to have leaked.
Another thing to note is that the JS heap space used by each compartment is now reported. Also, the fraction of the JS heap that isn’t currently used by any particular compartment is also reported:
Once this change landed, it didn’t take long to see that the “gc-heap-chunk-unused” number could get very large. In particular, if you browsed for a while, then closed all tabs except about:memory, then triggered heap minimization (via the buttons at the bottom of about:memory), you’d often see very large “gc-heap-chunk-unused” numbers. It turns out this is caused by fragmentation. The JS heap is broken into 1MB chunks, and often you’d end up with with a lot of almost-empty chunks, but they’d have a small number of long-lived objects in them keeping them alive, and thus preventing them from being deallocated.
Reduced JavaScript heap fragmentation
Fortunately, Gregor Wagner had already anticipated this, and he tightened his grasp on the 2011 MemShrink MVP award by greatly reducing this fragmentation in the JavaScript heap. Parts of Firefox itself are implemented in JavaScript, and many objects belonging to Firefox itself (more specifically, objects in the “system principal” and “atoms” compartments) are long-lived. So Gregor added simple chunk segregation; objects belonging to Firefox get put in one group of chunks, and all other objects (i.e. those from websites) get put in a second group of chunks. This made a huge difference. See this comment and subsequent comments for some detailed measurements of a short browsing session; in short, the size of the heap was over 5x smaller (21MB vs. 108MB) after closing a number of tabs and forcing garbage collection. Even if you don’t force garbage collection, it still helps greatly, because garbage collection happens periodically anyway, and longer browsing sessions will benefit more than shorter sessions.
This change will help everyday browsing a lot. It will also help with the perception of Firefox’s memory usage — once you learn about about:memory, an obvious thing to try is to browse for a while, close all tabs, and see what the memory usage looks like. Prior to this patch, the memory usage was often much higher than it is on start-up. With this patch, the usage is much closer to the usage seen at start-up. Ideally, it would be the same, and Justin Lebar opened a bug to track progress on exactly this issue.
There’s still room for reducing fragmentation in the JavaScript heap further. Kyle Huey has some good ideas in this bug.
Other bits and pieces
- Chris Pearce finished a major refactoring of media code. Previously, every media (<audio> and <video>) element in a page required three threads (four on Linux). And each thread has a stack. On Linux, the stack is 8MB, on Windows it’s 1MB, on Mac it’s 64KB. (Edit: Robert O’Callahan pointed out in the comments that this space is not necessarily committed, which means they’re not really costing anything other than virtual memory space.) Webpages can have dozens, even hundreds of media elements, so these stacks can really add up. Chris changed things so that each media element has a single thread. This really helps on complicated web sites/apps like The Wilderness Downtown, ROME, and WebGL Quake. (There is also a bug open to reduce the thread stack size on Linux; 8MB is excessive.) Chris only just landed these patches on mozilla-inbound, he deliberately waited until after the FF7 deadline to maximize testing time. Assuming there are no problems, this improvement will be in FF8.
- Jesse Ruderman tweaked some of his fuzzing tools to look for leaks and found four new ones.
- Mounir Lamouri landed some memory reporters for the DOM. They’re currently disabled while he extends them and makes that they’re reporting sensible numbers.
- I created mlk-fx8, a bug for tracking leaks and quasi-leaks reported against Firefox 8.
Quantifying progress
I’m going to attempt to quantify MemShrink’s progress in these weekly reports. It’s not obvious what’s the best way to do this. The MemShrink wiki page discusses this a bit. I’m going to do something crude: just count the number of bugs annotated with “MemShrink”, and track this each week. Here are the current counts:
- P1: 18
- P2: 44
- P3: 25
- Unprioritized: 2
Obviously, this is a flawed way to measure progress; for example, if we improve our leak-detection efforts, which is a good thing, we’ll get more bug reports. But hopefully these numbers will trend downwards in the long term.
I’m also wondering if my choice to have three priority levels was a mistake, if only for the reason that people like to pick the middle item, so P2 will always dominate. If we had four priority levels, we’d be forced to prioritize all those middling bugs up or down.
The minutes of today’s meeting are available here. Thanks to Jesse for taking them.