Thursday, December 11, 2008

Firefox 3.1 Beta 2 on Linux uses less memory

I mentioned a couple of months ago that there was room to improve Firefox's memory use for font handling on Linux. With Firefox 3.1 Beta 2, you can now enjoy these improvements.

In the graph you can see how the memory use of Firefox on Linux has changed during development for Firefox 3.1. The y-axis represents the average resident physical memory in bytes used by the Firefox process while cycling through 400 or so pages 5 or 10 times.

There are six traces here. The three overlapping traces that are steady at 128 MB until 26 September, and then jump to a steady 132 MB, track the memory use of Firefox 3.0. The 4 MB jump is not actually a change in the application but a change to the test producing the data. The important thing is that the same test is also run on the development builds.

The other three overlapping traces track Minefield during its development for Firefox 3.1. At the end of August, memory use was very similar to Firefox 3.0.

The 10 MB wobbles in the first half of September were due to glibc's memory allocator accidentally being used instead of jemalloc, and it looks like there was a memory leak introduced on 9 September that took a couple of days to plug.

These changes add up to Firefox 3.1 Beta 2 using only 64% of the memory used by Firefox 3.0 (for this particular test).

Some of the memory savings from font selection redesign followed from performance improvements that meant that less caching was required to maintain responsiveness, but much of the savings came from taking more care in managing font data from fontconfig.

Fontconfig serves more than one purpose: it provides configuration that gives users excellent control over which fonts they prefer and how they like their fonts rendered, and it also provides an automatically updated database of properties of every font installed on the system.

The font property database is shared by applications so that its use can be memory efficient. However, sharing the data is only possible while using the data in a read-only manner. If data is modified from its format in the database, it must be copied.

Functions such as FcFontRenderPrepare, FcFontSetMatch, and FcFontSetList modify the data, and so return copies. It is best to avoid holding onto these copies for longer than necessary. On the other hand, functions such as FcConfigGetFonts and FcFontSetSort return references to shared data. Much of the memory savings mentioned above were achieved by keeping references to shared data instead of copies of modified data.

Fewer fonts is definitely something worth investigating for mobile. I'm guessing the data here still includes at least 10-15 MB of font data, and that would be directly dependent on the number of fonts used.

Reducing the number of variations of each character would mean less information to manage and thus less memory.

Ideally it wouldn't matter if the characters were distributed across several fonts, each font supporting a different writing script. However, the number of glyphs cached in cairo is currently affected by a per-scaled-font limit, so merging separate fonts for different scripts into a single font would likely save some memory, but perhaps cost some performance.