DEV Community

loading...

Taking Firefox memory usage under control on Linux

msugakov
・4 min read

Life was easy when Firefox was 32-bit and single-process.
In 2021 it is 64 bit, launches bunch of sub-processes, and with many open tabs I routinely see Firefox processes allocate 16Gb of ram and 20Gb of swap slowing down everything else.

I'm using Ubuntu 20.04 and here's what helped me contain unbounded memory usage. Steps for other Linux distros might be similar.

1. Enable cgroups v2 and swap control

  • Open /etc/default/grub for editing (don't forget sudo) and find GRUB_CMDLINE_LINUX_DEFAULT there. Add systemd.unified_cgroup_hierarchy=1 and swapaccount=1 to it.

Here's how my looks like:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash systemd.unified_cgroup_hierarchy=1 swapaccount=1"
Enter fullscreen mode Exit fullscreen mode
  • Run sudo update-grub.

  • Reboot.

  • Test if cgroups v2 are enabled by running mount -t cgroup2. The output should be similar to this:

$ mount -t cgroup2
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate)
Enter fullscreen mode Exit fullscreen mode

What this does?

systemd.unified_cgroup_hierarchy=1 enables cgroups v2 support, that's what will enforce memory limits.

Be aware that once you enable v2, software that uses cgroups v1 (I imagine old Docker versions) may stop working. If you'll run into issues with older software, you know what could be a reason.

swapaccount=1 enables limiting swap usage. If it isn't enabled, cgroups will only enforce memory limits for RAM but not swap and so Firefox processes will not go over RAM limit but will push everything else into swap.

Read here and here if you'd like to learn more about swapaccount.

2. Edit launcher

I'm using xfce and so I can edit Firefox launch shortcut from the menu. You might do similar depending on how you start the browser.

Firefox Launcher settings

  • The launch command should be:
systemd-run --unit=my-firefox --user --scope -p MemoryHigh=6G -p MemoryMax=7G -p MemorySwapMax=0 firefox
Enter fullscreen mode Exit fullscreen mode
  • From now use this command/launcher to start the browser.

What this does?

systemd-run allows you to start a process with ad-hoc settings under control of systemd and cgroups without having to create so-called unit files. In this case we're starting firefox but you can apply this to other programs of course.

--unit=my-firefox gives a name to a systemd "scope" where firefox process will execute. You can omit this parameter or rename it as you wish. I find it useful to give scope some name to be able to more easily diagnose it later.

--user tells to run scope in your "user" slice, not in "system". This allows process to be started without asking your password.

--scope configures how process is started. Frankly I don't know what this does, but you need it.

-p MemoryHigh=6G sets 6 gigabyte "soft hard" limit on the amount of RAM Firefox processes may allocate. Firefox may request more memory but OS will resist by slowing down allocation. Practically, I don't see usage going much more that the value of this setting.

-p MemoryMax=7G sets 7 gigabyte "hard" limit on the amount of RAM for Firefox. If it tries to allocate that much, its processes will be killed. You may keep this setting if you want to protect other processes on your system from Firefox going crazy some day.

-p MemorySwapMax=0 does not allow Firefox use swap. In my experiments, Firefox performance gets worse if small amount of swap is allowed. If large amounts (>10G) of swap are allowed, Firefox will actively push out lots of memory there and can run overall ok but it wears SSD.

Read about Memory* properties in man systemd.resource-control.

3. Decrease amount of Firefox processes

  • Open browser preferences, about:preferences
  • Scroll to "Performance", uncheck "Use recommended performance settings"
  • Change "Content process limit" to 2

Alt Text

What this does?

Firefox uses sub-processes to speed up page rendering. The problem is that each sub-process uses lots of RAM. Firefox decides their count automatically and for me the count seems to be 8. Each subprocess using 2Gb of memory easily pushes overall usage to 16Gb or more.

More info at https://support.mozilla.org/en-US/kb/performance-settings.

4. Test and diagnose

Once you started the browser you can see its memory usage with this command

systemctl --user show my-firefox.scope | grep Memory
Enter fullscreen mode Exit fullscreen mode

Here's the output for me showing that the current usage is 5.5Gib.

MemoryCurrent=5596528640
EffectiveMemoryNodes=
AllowedMemoryNodes=
MemoryAccounting=yes
DefaultMemoryLow=0
DefaultMemoryMin=0
MemoryMin=0
MemoryLow=0
MemoryHigh=6442450944
MemoryMax=7516192768
MemorySwapMax=0
MemoryLimit=infinity
Enter fullscreen mode Exit fullscreen mode
  • Load many tabs and observe MemoryCurrent value. If at some point the browser freezes and you see that MemoryCurrent is close to or above MemoryHigh, you may need to tune settings. If things run smoothly all the time, consider decreasing MemoryHigh.

5. Tune settings

For me Firefox content processes each use 1.5-2.3Gb at peak load, and so MemoryHigh value should be greater than N*2.3Gb where N is the number of content processes you've configured in browser settings.
You also need to include some non-trivial amount for the parent Firefox process and other stuff that it spawns.
If your machine is low on memory, consider decreasing N, i.e. further decrease amount of content processes in the browser configuration.

Discussion (0)