I’ve spent a lot of time during the years fixing nautilus memory use. I noticed the other day that it seemed to be using a lot of memory again, doing nothing but displaying the desktop:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 14315 alex 20 0 487m 46m 15m S 0.3 1.2 0:00.86 nautilus
So, its time for another round of de-bloating. I fired up massif to see what used so much memory, and it turns out that there is a cache in GnomeBG that caches the original desktop background image. We don’t really need that since we keep around the final pixmap for the background.
It turns out that my desktop image is 2560×1600, which means the unscaled pixbuf uses 12 megs of memory. Just fixing this makes things a bit better:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 16129 alex 20 0 538m 33m 15m S 4.9 0.8 0:00.87 nautilus
However, looking at the actual allocations in massif its obvious that we’re not actually using this much memory. For a short time when creating the desktop background pixmap we do several large temporary allocations, but these are quickly freed. So, it seems we’re suffering from the heap growing and then not being returned to the OS due to fragmentation.
It is ‘well known’ that glibc uses mmap for large (> 128k by default) allocations and that such allocations should be returned to the OS directly when freed. However, this doesn’t seem to happen for some reason. Lots of research follows…
It turns out that this isn’t true anymore, since about 2006. Glibc now uses a dynamic threshold for when to start using mmap for allocations. It uses the size of freed mmaped memory chunks to update the threshold, and this is causing problems for nautilus which has a behaviour where almost all allocations are small or medium sized, but there are a few large allocations when handling the desktop background. This is leading to several large temporary allocations going to the heap, never to be returned to the OS.
Enter mallopt(), with lets us set a static mmap limit. So, we set this back to the old value of 128k:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4971 alex 20 0 479m 26m 15m S 0.0 0.7 0:00.90 nautilus
Not bad. Dropped 20 meg of resident size with a few hours of work. Now nautilus isn’t leading the pack anymore but comes after apps like gnome-panel, gnome-screensaver and gnome-settings-daemon.