Adaptive Memory Behaviour
The biggest news this week was that Justin Lebar landed code to make Firefox’s memory consumption adaptive on Windows. The code works by wrapping VirtualAlloc() and some similar OS-level allocation functions. Each time memory is allocated, the amount of available virtual and physical memory is measured by the wrapper. If either of those amounts are below a threshold, a memory pressure event is triggered, which causes numerous components within Firefox to take steps to reduce their memory consumption.
It might not sound like it, but this is a big deal, and it was a MemShrink:P1 bug. Firefox runs on a huge variety of machines and devices, and trying to find one-size-fits-all heuristics for discarding regenerable data is a recipe for unhappiness somewhere. Adaptive behaviour is much better.
The initial settings for this feature are conservative, and some tuning may be needed.
- The threshold used for virtual memory is 128MB, i.e. if the amount of available virtual memory drops below 128MB a memory pressure event is triggered. (This number can be changed in about:config via the “memory.low_virtual_memory_threshold_mb” setting.) Hopefully this will reduce the number of OOM crashes that occur on Windows.
- The threshold used for physical memory is 0, which means that it is currently ignored. (This number can be changed in about:config via the “memory.low_physical_mem_threshold_mb” setting.) The reason for ignoring it currently is that low physical memory may be caused by a program other than Firefox — we don’t want to start discarding data if Firefox is only using a small fraction of physical memory. In the future we can probably do better here by triggering memory pressure events if the fraction of physical memory used by Firefox exceeds some threshold; hopefully this will avoid paging when memory usage is high.
- Memory pressure events are throttled so they aren’t sent more than once every 10 seconds. (This number can be changed in about:config via the “memory.low_physical_memory_notification_interval_ms” setting.) This prevents thrashing in cases where the memory pressure events don’t help reduce memory consumption.
Memory pressure events are also currently unevenly observed — plenty of data could be dropped that currently isn’t — so there is room for improvement there.
Finally, there’s another bug still open to add similar adaptive behaviour on Mac, Linux and Android. Note also that memory pressure events are also triggered on Android when Firefox goes into the background.
There has been good news for add-ons: the #1, #6 and #8 most popular add-ons on AMO have all recently seen some MemShrink-related improvements.
- Wladimir Palant fixed an intermittent zombie compartment in AdBlock Plus. This fix is available in AdBlock Plus 2.0.1.
- Jan Honza Odvarko fixed a bug in Firebug that was causing it to use and hold onto excessive amounts of memory when websites chunked files through XMLHTTPRequest. This fix is available in Firebug 1.9b3.
- Nils Maier added some memory reporters to DownThemAll! These show up in the “Other Measurements” list in about:memory, and may help the DownThemAll! developers diagnose leaks and excessive memory consumption caused by the add-on. These are available in the DownThemAll! nightly builds.
Adding memory reporters to add-ons is a really good thing to do, and I plan to write some documentation to encourage other add-on developers to follow suit. However, if you are an add-on developer and are thinking of doing this, I need to stress one thing: the reports must have KIND_OTHER so that they end up in the “Other Measurements” list in about:memory. If they are put in the “explicit” tree, then some memory bytes may be counted twice (once by Firefox, once by the add-on) which will completely screw up about:memory’s results.
I landed several improvements to memory reporters.
- I fixed two bugs in the JS memory reporter that caused the size of the JS heap to be over-estimated by about 5%. Prior to this fix, “explicit”, “gc-heap-chunk-dirty-unused”, and “heap-unclassified” were all inflated slightly. I also added an assertion to prevent similar bugs happening again.
- I added another memory reporter for the startup cache, called “explicit/startup-cache/data”. This is often several MB shortly after start-up, but it tends to drop to almost zero after a while.
- I updated the xpti and prefixset memory reporters to the new style. This means they now measure slop bytes and are integrated with DMD. I also added SizeOfExcludingThis() functions to nsTArray and nsTHashtable, which gives the same benefits to all memory reporters that measure these basic types.
Here are the current bug counts.
- P1: 26 (-2/+1)
- P2: 139 (-6/+6)
- P3: 64 (-2/+2)
- Unprioritized: 0 (-1/+0)
Nice to see the total count drop, even if only by one.
Due to the Christmas break there won’t be a MemShrink meeting nor a MemShrink progress report next week. I’ll be back in two weeks, enjoy the break!