Categories
about:memory Firefox Memory consumption MemShrink

MemShrink progress, week 26

It’s been six months since MemShrink started!  Here are this week’s events of note.

Memory Reporting

I integrated DMD support into Firefox.  This is a big deal because DMD is crucial for improving the coverage and correctness of memory reporters.  There are several consequences of this.

  • You no longer need to apply a patch to Firefox if you want to use DMD, you just have to configure with --enable-dmd.  (Full instructions are here.)
  • Any memory reporter written in the new style (i.e. using a nsMallocSizeOfFun function created with NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN) will automatically get coverage in DMD.
  • DMD finds bugs in memory reporters, but it can also find bugs elsewhere.  For example, this week it found that some BaseShapes were being shared incorrectly, which Brian Hackett fixed.

I updated the layout memory reporters to use the new style.  I also updated the documentation on writing memory reporters, to cover more complicated topics like how to measure classes that involve inheritance.  I also added a request:  if you write a memory reporter, please add me as a co-reviewer.

Johnny Stenback implemented per-window DOM memory reporters, which gives much more detail for DOM memory usage in about:memory.  Here’s an example:

per-window dom reporter output in about:memory

Memory Usage Improvements

Boris Zbarsky lazily initialized some rulehash tables, saving about 45KB per blank tab;  this is a nice win for those people who have on-demand tab loading combined with sessions with many tabs.  The same patch also made one of the rulehash tables smaller when it is initialized, which can cause multi-MB savings on workloads of only a few tabs.

Bobby Holley fixed a bad memory leak in xpconnect that could cause unbounded amounts of memory to be leaked, albeit in somewhat unusual circumstances.  The bug was only in Firefox 9 and Firefox 10;  it’s been fixed for 10, and the patches to fix for 9 are ready to land.

Fabrice Desré fixed a regression that caused a zombie compartment when visiting addons.mozilla.org.

Bug Counts

Here are the current bug counts.

  • P1: 27 (-1/+1)
  • P2: 139 (-5/+3)
  • P3: 62 (-0/+2)
  • Unprioritized: 1 (-0/+1)

That’s a net change of +1, and we only had to triage seven bugs in today’s meeting.  And if the trees hadn’t been closed for the past few days I could have fixed two more P2 bugs.

Just for fun, I also counted the number of RESOLVED FIXED (i.e. genuine, not duplicates or invalid) MemShrink bugs.

  • P1: 29
  • P2: 70
  • P3: 14
  • Unprioritized: 35

(If you’re wondering why the number of unprioritized fixed bugs is so high, it’s because MemShrink bugs are only prioritized in MemShrink meetings, which means that any bug that gets filed and fixed in less than 7 days doesn’t get prioritized.)

So there are more bugs still open than have been fixed, but the rate of bug growth is close to zero.

Categories
about:memory Firefox Memory consumption MemShrink

MemShrink progress, week 25

It was a good week for MemShrink.

ObjShrink

The biggest news this week is that Brian Hackett landed his objshrink work.  This has roughly halved the size of Firefox’s representation of JavaScript objects.  It’s also reduced the amount of memory Firefox uses for shapes, a related data structure.  If  you look at about:memory you can see that “gc-heap/objects” and “gc-heap/shapes” entries account for many MBs of memory, so this is a big win.  Read here (under the “Objects” and “Shape” headings) if you want more details.

Memory Reporting

I added some more JavaScript memory reporters and fixed some problems with the existing ones.  Specifically…

  • New: “runtime/threads/temporary” counts various pieces of short-lived data, mostly parse nodes.  It sometimes spikes up to multiple MBs.
  • New: “runtime/threads/normal” measures thread data on the heap that isn’t covered by “runtime/threads/temporary”.  It’s normally a few 100s of KBs.
  • New: “runtime/contexts” measures JSContexts and various related structures, which usually account for a few 10s or 100s of KB.
  • New/fixed: “runtime/threads/regexp-code” measures code generated by the regexp compiler.  This was previously measured under “mjit-code/regexp” but that reporter was broken recently when the location of this generated code was moved, so I fixed it.
  • Fixed: “runtime/atoms-table” and “runtime/runtime-object” are existing reporters that together often account for up to 4.5MB.  They were incorrectly marked as measuring non-heap memory instead of heap memory, meaning that the “explicit” and “heap-unclassified” totals were both incorrectly inflated by that amount.  While fixing this, I also confirmed that we weren’t making the same mistake with any of our other memory reporters.
  • Renamed: “runtime/threads/stack-committed” was previously called “stack-size”.  I renamed it to go with the other “runtime/threads” reports because that’s where it conceptually belongs.

I also added a memory reporter for XPConnect.  It typically accounts for 1MB or more.

I have a lot more work in the pipeline to improve the coverage and correctness of memory reporters.  More about this in the coming weeks as I land the relevant patches!

Other

Joel Maher got RSS memory measurements working for Android on Talos, Mozilla’s performance regression testing suite.  This was a MemShrink:P1 bug.  Graphs of the live data can be seen here.

Benoit Jacob made some improvements how Firefox manages and reports memory used by WebGL.

Bug Counts

Here’s the current bug count.

  • P1: 27 (-1/+1)
  • P2: 141 (-3/+5)
  • P3: 62 (-1/+2)
  • Unprioritized: 0 (-0/+0)

Only three more MemShrink bugs than this time last week!  Pretty good.

Categories
about:memory Memory consumption MemShrink

MemShrink progress report, week 24

Something that happened a while ago but I failed to notice was that Chris Leary added a regexp cache which, among other things, is flushed on every GC.  This fixed an existing problem where cold regexps were not being discarded, which was a MemShrink:P1 bug because 10s or even 100s of MBs of compiled regexp code could accumulate in some circumstances.  Nice work, Chris!

Andrew McCreight fixed two leaks (here and here) involving WeakMaps.  WeakMaps are an EcmaScript 5 feature and so are not used that much at the moment, but their popularity will increase over time.

I landed some memory reporter infrastructure changes.  These will make it much easier to integrate DMD with Firefox, which will help drive about:memory’s “heap-unclassified” number down.  They also do some sanity checking of memory reporters, and this checking has already found some bugs in existing reporters.

Terrence Cole made the JS engine to a “shrink” GC on memory pressure events, such as when about:memory’s “minimize memory usage” button is pressed.  A “shrink” GC is one that causes unused pages to be decommitted.

I wrote two pieces of documentation.

  • The first is a guide to zombie compartments, including instructions on how to test if an add-on causes them.  This guide is similar in spirit to an old blog post of mine, but explains things more carefully.  There is a QA test day planned for Friday, December 16, and hopefully some extensive add-on leak testing will happen on that day.
  • The second is a guide to implementing memory reporters.  Please read it if you ever have to implement one.

In publicity news, ZDNet published a story about how Google’s +1 buttons consume a lot of memory, particular in the newly redesigned Google Reader.  The author used Firefox’s about:memory page to determine this, which enabled him to point the finger at Google’s JS code instead of Firefox.  (Dietrich Ayala wrote about this topic previously, and wrote the Wallflower add-on in response;  the Antisocial subscription for AdBlock Plus apparently has the same effect.)

Here’s the current bug count.

  • P1: 27 (-5/+1)
  • P2: 139 (-4/+11)
  • P3: 61 (-0/+1)
  • Unprioritized: 0 (-4/+0)

The P1s went down because in today’s MemShrink meeting we reprioritized several that are now less important than they were.

Categories
about:memory Firefox Memory consumption MemShrink

MemShrink progress report, week 22

This was a quieter week.

Andrew McCreight finished his static analysis to detect cycle collector leaks.  See the details in the bug (and talk to Andrew) if you are interested in using this analysis.

I shrunk the size of js::HashTable by 4 bytes on 32-bit platforms and 8 bytes on 64-bit platforms.  This saves a few 10s or 100s of KB on typical workloads.

Marco Bonardo decreased the default maximum page size of SQLite connections, which can reduce SQLite memory usage somewhat.

Olli Pettay avoided some wasted space in one of the cycle collector’s data structures.  The cycle collector uses lots of memory but for a short time when it runs;  this change will reduce the size of this memory spike.

Gian-Carlo Pascutto added a memory reporter for one of the data structures used by the url-classifier.  This shows up in about:memory under “explicit/storage/prefixset” and is often over 1MB.

Justin Lebar improved the measurement of nsTArray’s memory usage, which will reduce the size of “heap-unclassified” in about:memory by a small amount.

Justin also wrote a good blog post about the challenges of addressing leaks in add-ons.

We only had seven new MemShrink bugs to triage in today’s meeting;  I’m pretty sure that is the fewest we’ve ever had.  Here are the current bug counts.

  • P1: 29 (+1/-1)
  • P2: 127 (-2/+3)
  • P3: 58 (-3/+2)
  • Unprioritized: 0 (-0/+0)

These counts are notable because the total number (214) is the same as last week!  Maybe the number will start dropping soon.

One thing worth pointing out about the +/- numbers is that if a bug is opened and closed between my weekly reports, it does not get counted in the +/- numbers.  In a way this is good, because it means that duplicate bugs and invalid bugs don’t affect the numbers.  But it also fails to capture bugs that were reported and fixed quickly.  (I usually describe such bugs in my posts, however.)

Categories
about:memory Firefox Garbage Collection Memory consumption MemShrink SQLite

MemShrink progress, week 21

MemShrink:P1 Bugs fixed

Terrence Cole made a change that allows unused arenas in the JS heap to be decommitted, which means they more or less don’t cost anything.  This helps reduce the cost of JS heap fragmentation, which is a good short-term step while we are waiting for a compacting garbage collector to be implemented.  Terrence followed it up by making the JS garbage collector do more aggressive collections when many decommitted arenas are present.

Justin Lebar enabled jemalloc on MacOS 10.7.  This means that jemalloc is finally used on all supported versions of our major OSes: Windows, Mac, Linux and Android.  Having a common heap allocator across these platforms is great for consistency of testing and behaviour, and makes future improvements involving jemalloc easier.

Gabor Krizsanits created a new API in the add-on SDK that allows multiple sandboxes to be put into the same JS compartment.

Other Bugs Fixed

I registered jemalloc with SQLite’s pluggable allocator interface.  This had two benefits.  First, it means that SQLite no longer needs to store the size of each allocation next to the allocation itself, avoiding some clownshoes allocations that wasted space.  This reduces SQLite’s total memory usage by a few percent.  Second, it makes the SQLite numbers in about:memory 100% accurate;  previously SQLite was under-reporting its memory usage, sometimes significantly.

Relatedly, Marco Bonardo made three changes (here, here and here) that reduce the amount of memory used by the Places database.

Peter Van der Beken fixed a cycle collector leak.

I tweaked the JavaScript type inference memory reporters to provide better coverage.

Jiten increased the amount of stuff that is released on memory pressure events, which are triggered when Firefox on Android moves to the background.

Finally, I created a meta-bug for tracking add-ons that are known to have memory leaks.

Bug Counts

I accidentally deleted my record of the live bugs from last week, so I don’t have the +/- numbers for each priority this week.

  • P1: 29 (last week: 35)
  • P2: 126 (last week: 116)
  • P3: 59 (last week: 55)
  • Unprioritized: 0 (last week: 5)

The P1 result was great this week — six fewer than last week.  Three of those were fixed, and three of those I downgraded to P2 because they’d been partially  addressed.

For a longer view of things, here is a graph showing the MemShrink bug count since the project started in early June.

memshrink bug count

There was an early spike as many existing bugs were tagged with “MemShrink”, and a smaller spike in the middle when Marco Castellucio tagged a big pile of older bugs.  Other than that, the count has marched steadily upward at the rate of about six per week.  Many bugs are being fixed and definite improvements are being made, but this upward trend has been concerning me.

Future Directions

So in today’s MemShrink meeting we spent some time discussing future directions of MemShrink.  Should we continue as is?  Should we change our focus, e.g. by concentrating more on mobile, or setting some specific targets?

The discussion was long and wide-ranging and not easy to summarize.  One topic was “what is the purpose of MemShrink?”  The point being that memory usage is really a secondary measure.  By and large, people don’t really care how many MB of memory Firefox is using;  they care how responsive it is, and it’s just assumed that reducing memory usage will help with that.  With that in mind, I’ll attempt to paraphrase and extrapolate some goals (apologies if I’ve misrepresented people’s opinions).

  • On 64-bit desktop, the primary goal is that Firefox’s performance should not degrade after using it heavily (e.g. many tabs) for a long time.  This means it shouldn’t page excessively, and that operations like garbage collection and cycle collection shouldn’t get slower and slower.
  • On mobile, the primary goal probably is to reduce actual memory usage.  This is because usage on mobile tends to be lighter (e.g. not many tabs) so the longer term issues are less important.  However, Firefox will typically be killed by the OS if it takes up too much memory.
  • On 32-bit desktop, both goals are relevant.

As for how these goals would change our process, it’s not entirely clear.  For desktop, it would be great to have a benchmark that simulates a lot of browsing (opening and closing many sites and interacting with them in non-trivial ways).  At the end we could measure various things, such a memory usage, garbage and cycle collection time, and we could set targets to reduce those.  For mobile, the current MemShrink process probably doesn’t need to change that much, though more profiling on mobile devices would be good.

Personally, I’ve been spreading myself thinly over a lot of MemShrink bugs.  In particular, I try to push them along and not let them stall by doing things like trying to reproduce them, asking questions, etc.  I’ve been feeling lately like it would be a better use of my time to do less of that and instead dig deeply into a particular area.  I thought about working on making JS script compilation lazy, but now I’ve decided instead to focus primarily on improving the measurements in about:memory, in particular, reducing the size of “heap-unclassified” by improving existing memory reporters and adding new ones. I’ve decided this because it’s an area where I have expertise, clear ideas on how to make progress, and tools to help me.  Plus it’s important;  we can’t make improvements without measurements, and about:memory is the best memory measurement tool we have.  Hopefully other people agree that this is important to work on 🙂

Categories
about:memory DMD Firefox Valgrind

Reducing about:memory’s “heap-unclassified” measurement with DMD

about:memory is a really useful tool, but everyone always complains about the “heap-unclassified” number being too high.  It’s too high because we don’t have enough memory reporters implemented.

DMD is a tool that identifies where new memory reporters should be added to reduce “heap-unclassified”.  I’ve been using it for a couple of months now, and I’ve just written instructions on how to use it.  It’s not easy, but hopefully it’s doable.

It’s probably worth pointing out that we have a pretty good handle on what needs to be done to reduce “heap-unclassified” significantly — check out the list of memory reporters to be implemented.  Almost all of those bugs were filed based on data from DMD.  The single most important bug in that list is the one to add missing style reporters;  I see multiple megabytes of CSS stuff all the time in DMD’s output.

Categories
about:memory Firefox Garbage Collection JägerMonkey Memory consumption MemShrink Tracemonkey

SpiderMonkey is on a diet

One thing I’ve learnt while working for Mozilla is that a web browser can be characterized as a JavaScript execution environment that happens to have some multimedia capabilities.  In particular, if you look at Firefox’s about:memory page, the JS engine is very often the component responsible for consuming the most memory.

Consider the following snapshot from about:memory of the memory used by a single JavaScript compartment.

about:memory snapshot

(For those of you who have looked at about:memory before, some of those entries may look unfamiliar, because I landed a patch to refine the JS memory reporters late last week.)

There is work underway to reduce many of the entries in that snapshot.  SpiderMonkey is on a diet.

Objects

Objects are the primary data structure used in JS programs;  after all, it is an object-oriented language.  Inside SpiderMonkey, each object is represented by a JSObject, which holds basic information, and possibly a slots array, which holds the object’s properties. The memory consumption for all JSObjects is measured by the “gc-heap/objects/non-function” and “gc-heap/objects/function” entries in about:memory, and the slots arrays are measured by the “object-slots” entries.

The size of a non-function JSObject is currently 40 bytes on 32-bit platforms and 72 bytes on 64-bit platforms.  Brian Hackett is working to reduce that to 16 bytes and 32 bytes respectively. Function JSObjects are a little larger, being (internally) a sub-class of JSObject called JSFunction.  JSFunctions will therefore benefit from the shrinking of JSObject, and Brian is slimming down the function-specific parts as well.  In fact, these changes are complete in the JaegerMonkey repository, and will likely be merged into mozilla-central early in the Firefox 11 development period.

As for the slots arrays, they are currently arrays of “fatvals” A fatval is a 64-bit internal representation that can hold any JS value — number, object, string, whatever.  (See here for details, scroll down to “Mozilla’s New JavaScript Value Representation”;  the original blog entry is apparently no longer available).  64-bits per entry is overkill if you know, for example, that you have an array full entirely of integers that could fit into 32 bits.  Luke Wagner and Brian Hackett have been discussing a specialized representation to take advantage of such cases.  Variations on this idea have been tried twice before and failed, but perhaps SpiderMonkey’s new type inference support will provide the right infrastructure for it to happen.

Shapes

There are a number of data structures within SpiderMonkey dedicated to making object property accesses fast.  The most important of these are Shapes.  Each Shape corresponds to a particular property that is present in one or more JS objects.  Furthermore, Shapes are linked into linear sequences called “shape lineages”, which describe object layouts.  Some shape lineages are shared and live in “property trees”.  Other shape lineages are unshared and belong to a single JS object;  these are “in dictionary mode”.

The “shapes/tree” and “shapes/dict” entries in about:memory measure the memory consumption for all Shapes.  Shapes of both kinds are the same size;  currently they are 40 bytes on 32-bit platforms and 64 bytes on 64-bit platforms.  But Brian Hackett has also been taking a hatchet to Shape, reducing them to 24 bytes and 40 bytes respectively.  This has required the creation of a new auxiliary BaseShape type, but there should be many fewer BaseShapes than there are Shapes.  This change will also increase the number of Shapes, but should result in a space saving overall.

SpiderMonkey often has to search shape lineages, and for lineages that are hot it creates an auxiliary hash table, called a “property table”, that makes lookups faster.  The “shapes-extra/tree-tables” and “shapes-extra/dict-tables” entries in about:memory measure these tables.  Last Friday I landed a patch that avoids building these tables if they only have a few items in them;  in that case a linear search is just as good.  This reduced the amount of memory consumed by property tables by about 20%.

I mentioned that many Shapes are in property trees.  These are N-ary trees, but most Shapes in them have zero or one child;  only a small fraction have more than that, but the maximum N can be hundreds or even thousands.  So there’s a long-standing space optimization where each shape contains (via a union) a single Shape pointer which is used if it has zero or one child.  But if the number of children increases to 2 or more, this is changed into a pointer to a hash table, which contains pointers to the N children.  Until recently, if a Shape had a child deleted and that reduced the number of children from 2 to 1, it wouldn’t be converted from the hash form back to the single-pointer.  I changed this last Friday.  I also reduced the minimum size of these hash tables from 16 to 4, which saves a lot of space because most of them only have 2 or 3 entries.  These two changes together reduced the size of the “shapes-extra/tree-shape-kids” entry in about:memory by roughly 30–50%.

Scripts

Internally, a JSScript represents (more or less) the code of a JS function, including things like the internal bytecode that SpiderMonkey generates for it.  The memory used by JSScripts is measured by the “gc-heap/scripts” and “script-data” entries in about:memory.

Luke Wagner did some measurements recently that showed that most (70–80%) JSScripts created in the browser are never run.  In hindsight, this isn’t so surprising — many websites load libraries like jQuery but only use a fraction of the functions in those libraries.  It wouldn’t be easy, but if SpiderMonkey could be changed to generate bytecode for scripts lazily, it could reduce “script-data” memory usage by 60–70%, as well as shaving non-trivial amounts of time when rendering pages.

Trace JIT

TraceMonkey is SpiderMonkey’s original JIT compiler, which was introduced in Firefox 3.5.  Its memory consumption is measured by the “tjit-*” entries in about:memory.

With the improvements that type inference made to JaegerMonkey, TraceMonkey simply isn’t needed any more.  Furthermore, it’s a big hairball that few if any JS team members will be sad to say goodbye to.  (js/src/jstracer.cpp alone is over 17,000 lines and over half a megabyte of code!)

TraceMonkey was turned off for web content JS code when type inference landed.  And then it was turned off for chrome code.  And now it is not even built by default.  (The about:memory snapshot above was from a build just before it was turned off.)  And it will be removed entirely early in the Firefox 11 development period.

As well as saving memory for trace JIT code and data (including the wasteful ballast hack required to avoid OOM crashes in Nanojit, ugh), removing all that code will significantly shrink the size of Firefox’s code.  David Anderson told me the binary of the standalone JS shell is about 0.5MB smaller with the trace JIT removed.

Method JIT

JaegerMonkey is SpiderMonkey’s second JIT compiler, which was introduced in Firefox 4.0.  Its memory consumption is measured by the “mjit-code/*” and “mjit-data” entries in about:memory.

JaegerMonkey generates a lot of code.  This situation will hopefully improve with the introduction of IonMonkey, which is SpiderMonkey’s third JIT compiler.  IonMonkey is still in early development and won’t be integrated for some time, but it should generate code that is not only much faster, but much smaller.

GC HEAP

There is a great deal of work being done on the JS garbage collector, by Bill McCloskey, Chris Leary, Terrence Cole, and others.  I’ll just point out two long-term goals that should reduce memory consumption significantly.

First, the JS heap currently has a great deal of wasted space due to fragmentation, i.e. intermingling of used and unused memory.  Once moving GC — i.e. the ability to move things on the heap — is implemented, it will pave the way for a compacting GC, which is one that can move live things that are intermingled with unused memory into contiguous chunks of memory.  This is a challenging goal, especially given Firefox’s high level of interaction between JS and C++ code (because moving C++ objects is not feasible), but one that could result in very large savings, greatly reducing the “gc-heap/arena/unused” and “gc-heap-chunk-*-unused” measurements in about:memory.

Second, a moving GC is a prerequisite for a generational GC, which allocates new things in a small chunk of memory called a “nursery”.  The nursery is garbage-collected frequently (this is cheap because it’s small), and objects in the nursery that survive a collection are promoted to a “tenured generation”.  Generational GC is a win because in practice the majority of things allocated die quickly and are not promoted to the tenured generation.  This means the heap will grow more slowly.

Is that all?

It’s all I can think of right now.  If I’ve missed anything, please add details in the comments.

There’s an incredible amount of work being done on SpiderMonkey at the moment, and a lot of it will help reduce Firefox’s memory consumption.  I can’t wait to see what SpiderMonkey looks like in 6 months!

Categories
about:memory Firefox Memory consumption MemShrink

MemShrink progress, week 12

about:memory improvements

Lots of changes were made to about:memory this week.

Justin Lebar landed a patch that provides detailed information about RSS, vsize and swap memory usage on Linux and Android.  (The patch was backed out due to a minor leak but I expect Justin will fix that and re-land it soon.)  This will help us understand memory usage that is not covered by the “Explicit Allocations” tree in about:memory, such as memory used for static code and data, and it should be particularly useful on Android.  The contents of the new trees are hidden by default;  you have to click on the tree heading to expand each one.

Kyle Huey split up about:memory’s layout measurements on a per-PresShell basis.  This makes it easy to see how much layout memory is being used by each web page.

Something I failed to mention last week was that with the landing of type inference, each JavaScript compartment has five new measurements: “object-main”, “script-main”, “tables”, “analysis-temporary”, and “object-empty-shapes”.

I converted some of the JavaScript memory reporters to use moz_malloc_usable_size to measure actual allocation sizes instead of requested allocation sizes.  This accounts for slop bytes caused by the heap allocator rounding up.  This is quite important — slop bytes can easily account for over 10% of the heap, and if we don’t account for them we’ll never get about:memory’s “heap-unclassified” number down.  Therefore I’ll be doing more of this in the future.  And it would be great if people writing new memory reporters can do the same thing!

Finally, on the topic of “heap-unclassified” number:  people often complain about it, so I’m happy to say that it is on a clear downward path.  Indeed, thanks to DMD, at the time of writing we have 16 open bugs to add new memory reporters for things that consume significant amounts of memory, and 13 of these are assigned.  I’m hoping that in a month or two the “heap-unclassified” number on development builds will typically be 10–15% rather than the 30–35% it usually is now.

Other things

I changed the growth strategy used for one of JaegerMonkey’s buffers to avoid large amounts of memory wasted due to slop bytes.  These buffers are short-lived so the fix doesn’t make a great difference to total memory consumption, but it does reduce the number of allocations and heap churn.

Marco Bonardo wrote about his recent changes to the handling of the places database.

Dietrich Ayala wrote about an experimental add-on that unloads tabs that haven’t been viewed in a while, which is an interesting idea.  I suspect the exact approach used in the add-on won’t be viable in the long run, but we can certainly benefit from doing a better job of discarding regenerable info that hasn’t been used in a while, particularly on mobile.

Bug counts

This weeks’s bug counts are as follows:

  • P1: 29 (-2, +2)
  • P2: 80 (-4, +8)
  • P3: 40 (-2, +4)
  • Unprioritized: 22 (-12, +12)

Just like last week, Marco Castelluccio tagged quite a lot of old bugs with “[MemShrink]”.  We had 45 unprioritized bugs at the start of this week’s meeting, and we got through more than 20 of them.

Some comments on last week’s post got me thinking about how to make it easier for more people to help with MemShrink.  For those who don’t have much coding experience, probably the best bet is to look at the list of unconfirmed bugs — these are problems reported by users where the particular problem hasn’t been identified.  Often they need additional effort to determine if they are reproducible, due to add-ons, etc.  For example, in bug 676872 a user was seeing very high memory usage, and it’s clear that it was caused by one or more of the 41(!) add-ons he had enabled.  Ideally that bug’s reporter would disable them selectively to narrow that down, but anyone could do likewise with some effort.

For those who do have coding experience, it would be worth looking at the list of bugs that have a “mentor” annotation.  For example, bug 472209 is about adding some graphing capability to about:memory.  Jezreel Ng made some excellent progress on this during his internship, it just needs someone to take over and finish it up.

Finally, for those who like a challenge or have some experience with Firefox’s code, the full list of unassigned bugs might be of interest.  There are currently 86 such bugs!  More than I’d like.

(BTW, I’ve added links for the three bug lists above to the MemShrink wiki page.)

On HIATUS

I will be on vacation for the next five weeks and the MemShrink progress report will be on hiatus during that time.  But MemShrink meetings will continue (except there won’t be one next week due to the Mozilla all-hands meeting).  I look forward to writing a bumper progress report on October 19, where I’ll be able to summarize everything that happened while I was away!

Categories
about:memory Firefox JägerMonkey Memory consumption MemShrink SQLite

MemShrink progress, week 11

This week was quiet in terms of patches landed.

  • Marco Bonardo changed the way the places.sqlite database is handled. I’m reluctant to describe the change in much detail because I’ll probably get something wrong, and Marco told me he’s planning to write a blog post about it soon.  So I’ll just quote from the bug: “Globally on my system (8GBs) I’ve often seen places.sqlite cache going over 100MB, with the patch I plan to force a maximum of 60MB (remember this will vary based on hardware specs), that is a >40% improvement. We may further reduce in future but better being on the safe side for now.”  This was a MemShrink:P1 bug.
  • New contributor Sander van Veen knocked off another bug (with help from his friend Bas Weelinck) when he added more detail to the “mjit-code” entries in about:memory.  This makes it clear how much of JaegerMonkey’s code memory usage is for normal methods vs. memory for compiled regular expressions.
  • I rearranged nsCSSCompressedDataBlock to avoid some unnecessary padding on 64-bit platforms.  This can save a megabyte or two if you have several CSS-heavy (e.g. Gmail) tabs open.   It makes no difference on 32-bit platforms.

But it was a very busy week in terms of bug activity.  Let’s look at the numbers.

  • P1: 29 (-2, +2)
  • P2: 76 (-10, +20)
  • P3: 38 (-1, +2)
  • Unprioritized: 22 (-5, +23)

Several things happened here.

  • Marco Castelluccio looked through old bugs and found a lot (30 or more) that were related to memory usage and tagged them with “MemShrink”.
  • Nine new bugs were filed to reduce about:memory’s “heap-unclassified” number by adding memory reporters;  many of these were thanks to Boris Zbarsky’s insights into the output produced by DMD.
  • I closed out a number of bugs that were incomplete, stale, or finished;  this included some of those newly marked by Marco, and some ones that were already tagged with “MemShrink”.
  • I tagged five leaks that were found with the cppcheck static analysis tool.

We spent the entire MemShrink meeting today triaging unprioritized bugs and we got through 23 of them.  Of the remaining unprioritized bugs, the older ones tagged by Marco and the cppcheck ones (which I tagged after the meeting) constitute most of them.

It’s clear that the rate of problem/improvement identification is outstripping the rate of fixes.  We have a standing agenda item in MemShrink meetings to go through Steve Fink’s ideas list, but we haven’t touched it in the past two meetings because we’ve spent the entire time on triage.  And when we do go through that list, it will only result in more bugs being filed.  I’m hoping that this glut of MemShrink-tagged bugs is temporary and the new bug rate will slow again in the coming weeks.

In the meantime, if you want to help, please look through the lists of open bugs, or contact me if you aren’t sure where to start, and I’ll do my best to find something you can work on.  Thanks!

Categories
about:memory Firefox Garbage Collection Memory allocation Memory consumption MemShrink Tracemonkey Valgrind

MemShrink progress, week 9

Firefox 8 graduated to the Aurora channel this week, and the development period for what will become Firefox 9 began.  Lots of MemShrink activity happened this week, and I think all the changes listed below will make it into Firefox 8.

Avoiding Wasted Memory

I have blogged previously about memory wasted by “clownshoes” bugs.   Ed Morley found a webpage that resulted in 700MB of memory being wasted by the PLArena clownshoes bug.  Basically, on platforms where jemalloc is used (Windows, Linux), half the memory allocated by nsPresArena (which is built on top of PLArena) was wasted.  (On Mac the waste was 11%, because the Mac allocator rounds up less aggressively than jemalloc).

Fixing this problem properly for all PLArenas takes time because it requires changes to NSPR, so I made a spot-fix for the nsPresArena case.  This is a particularly big win on very large pages, but it saves around 3MB even on Gmail. This spot-fix has been granted beta approval and so will, barring disaster, make it into Firefox 7.

A Firefox Nightly user did some measurements with different browsers on the problematic page:

  • Firefox 8.0a1 before patch: 2.0 GB
  • Firefox 8.0a1 after patch: 1.3 GB
  • Latest Chrome canary build and dev (15.0.849.0): 1.1GB
  • Webkit2Process of Safari 5.1: 1.05 GB
  • Internet Explorer 9.0.2: 838 MB
  • Latest Opera Next 12.00: 727 MB

So this fix gets Firefox within spitting distance of other browsers, which is good!

In other developments related to avoiding wasted memory:

  • Luke Wagner discovered that, on typical websites, most JSScripts are byte-compiled but never run.  A JSScript roughly corresponds to a JavaScript function.  In hindsight, it’s not such a surprising result — Firefox byte-compiles all loaded JavaScript code, and you can imagine lots of websites use libraries like jQuery but only use a small fraction of the functions in the library.  Making byte-compilation lazy could potentially save MBs of memory per compartment.  But that will require some non-trivial reworking of the JS engine, and so is unlikely to happen in the short-term.
  • Kyle Huey avoided a small amount (~100KB per browser process) of waste due to rounding up in XPT arenas.

Improving about:memory

I made some progress on a Valgrind tool to help identify the memory that is currently reported only by the “heap-unclassified” bucket in about:memory.  It’s called “DMD”, short for “Dark Matter Detector”.  It’s in early stages and I still need to teach it about most of Firefox’s memory reporters, but it’s already spitting out useful data, which led to me and Ehsan Akhgari landing memory reporters for the JS atom table and the Hunspell spell checker.  We also now have some insight (here and here) about memory usage for very large pages.

Mounir Lamouri turned on the memory reporter for the DOM that he’s been working on for some time.  This shows up under “dom” in about:memory.  There are still some cases that require handling;  you can follow the progress of these here.

Andrew McCreight replaced about:memory’s buttons so you can force a cycle collection without also forcing a garbage collection, which may be useful in hunting down certain problems.

Finally, Sander van Veen added the existing “js-compartments-user” and “js-compartments-system” to the statistics collected by telemetry (his first landed patch!), and I did likewise for the “storage/sqlite” reporter.  I also added a new “tjit-data/trace-monitor” memory reporter that accounts for some of the memory used by TraceMonkey.

Miscellaneous

Igor Bukanov tweaked the handling of empty chunks by the JavaScript garbage collector.  That sounds boring until you see the results on Gregor Wagner’s 150-tab stress test: resident memory usage dropped 9.5% with all 150 tabs open, and dropped by 27% after all those tabs were closed.

Brian Hackett fixed a memory leak in type inference, which gets it one step closer to being ready to land.

Christian Höltje fixed a leak in his “It’s All Text” add-on that was causing zombie compartments.  This fix will be in version 1.6.0, which is currently awaiting to receive AMO approval, but can be obtained here in the meantime.  This fix and last week’s fix of a memory leak in LastPass are very encouraging — per-compartment reporters in about:memory have, for the first time, given add-on developers a reasonable tool for identifying memory leaks.  I hope we can continue to improve the situation here.  Several people have asked me for documentation on how to avoid memory leaks in add-ons.  I’m not the person to write that guide (I’m not a Gecko expert and I know almost nothing about add-ons) but hopefully someone else can step up to the plate.

Bug counts

Here’s the change in MemShrink bug counts.

  • P1: 30 (-0, +1)
  • P2: 64 (-4, +6)
  • P3: 36 (-5, +0)
  • Unprioritized: 1 (-2, +1)

Good progress on P3 bugs, but they’re the least important ones.  Other than that, new bugs are still being reported faster than they’re being fixed.  If you want to help but don’t know where to start, feel free to email me or ping me on IRC and I’ll do my best to help get you involved.