如何通过systemd将所有浏览器进程归入自定义cgroup并设置内存限制(Ubuntu环境)
我之前也遇到过类似的困扰——systemd接管cgroup后,确实没法像用cgmanager那样自由折腾了。不过好在systemd本身提供了完整的资源管控能力,下面是一套适配Ubuntu环境的解决方案,完全基于systemd原生工具,能自动把指定浏览器进程归入自定义cgroup,还能设置内存上限,而且尽量避免“漏网”的情况:
一、创建用户自定义Slice(核心配置)
首先我们要创建一个用户级的systemd slice,这就是我们的自定义cgroup,用来统一管控浏览器进程的资源。
- 在用户配置目录下创建slice文件:
mkdir -p ~/.config/systemd/user/ nano ~/.config/systemd/user/mybrowsers.slice
- 写入以下配置(根据你的需求修改内存限制数值):
[Unit] Description=自定义浏览器进程组(带内存限制) [Slice] MemoryMax=4G # 浏览器进程组的最大可用内存,比如设置为4GB MemoryHigh=3.5G # 可选:内存高水位线,超过后系统会主动回收内存,避免触发硬限制
- 重新加载用户级systemd配置,让新slice生效:
systemctl --user daemon-reload
二、为浏览器配置专属Systemd Service
接下来为每个浏览器创建用户级的service文件,强制它们启动时归入我们的自定义slice。
配置Firefox
创建~/.config/systemd/user/firefox.service:
[Unit] Description=Mozilla Firefox(归入自定义浏览器进程组) Documentation=man:firefox(1) [Service] Type=exec ExecStart=/usr/bin/firefox Slice=mybrowsers.slice # 可选:添加CPU限制,比如限制使用50%的CPU核心 CPUQuota=50% Restart=on-failure
配置Chrome
创建~/.config/systemd/user/chrome.service:
[Unit] Description=Google Chrome(归入自定义浏览器进程组) Documentation=man:chrome(1) [Service] Type=exec ExecStart=/opt/google/chrome/chrome Slice=mybrowsers.slice MemoryMax=4G # 也可以单独给Chrome设置不同的内存限制 Restart=on-failure
- 启用并启动这些服务:
systemctl --user enable --now firefox.service chrome.service
三、确保所有启动方式都纳入管控
直接调用浏览器二进制文件会绕开systemd service,所以我们要做两个小处理,避免“漏网”:
1. 命令行别名
在你的shell配置文件(比如~/.bashrc或~/.zshrc)中添加别名,让命令行启动也走systemd service:
echo "alias firefox='systemctl --user start firefox'" >> ~/.bashrc echo "alias chrome='systemctl --user start chrome'" >> ~/.bashrc
然后重新加载shell配置:
source ~/.bashrc
2. 修改桌面快捷方式
找到浏览器的桌面快捷方式文件(通常在~/.local/share/applications/或/usr/share/applications/),把Exec=行修改为通过systemd启动:
比如Firefox的.desktop文件,把原来的Exec=/usr/bin/firefox %u改成:
Exec=systemd-run --user --slice=mybrowsers.slice /usr/bin/firefox %u
这样不管是从桌面菜单启动,还是双击快捷方式,都会自动进入自定义slice。
四、验证配置有效性
配置完成后,我们可以检查是否生效:
- 启动浏览器,查看slice的状态:
systemctl --user status mybrowsers.slice
你应该能看到浏览器进程列在这个slice的下属进程中。
2. 查看内存限制是否正确应用:
cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/user@$(id -u).service/mybrowsers.slice/memory.max
输出的数值应该对应你设置的内存上限(比如4GB对应4294967296字节)。
五、备选方案:自动移动现有进程(无需修改启动方式)
如果你不想折腾启动方式的配置,也可以用一个轻量级的监控服务,自动把运行中的浏览器进程移到自定义slice里。虽然这属于轮询机制,但资源消耗极低,完全可以接受:
创建~/.config/systemd/user/browser-cgroup-monitor.service:
[Unit] Description=监控并自动移动浏览器进程到自定义slice [Service] Type=simple ExecStart=/bin/bash -c 'while true; do for pid in $(pgrep -f "/usr/bin/firefox\|/opt/google/chrome/chrome"); do systemctl --user set-property $pid Slice=mybrowsers.slice 2>/dev/null; done; sleep 5; done' Restart=always [Install] WantedBy=default.target
启用并启动这个监控服务:
systemctl --user enable --now browser-cgroup-monitor.service
它会每隔5秒检查一次浏览器进程,自动把它们归入自定义slice,不管你是怎么启动的浏览器。
备注:内容来源于stack exchange,提问作者Mikko Rantalainen




