oom-killer 在 Linux 用户中通常名声不佳。这可能是 Linux 仅在别无选择时才调用它的部分原因。它将交换桌面环境,删除整个页面缓存并清空每个缓冲区,然后最终杀死进程。至少我认为它会做到这一点。我还没有足够的耐心等待它,坐在一个没有反应的系统前面。
这让我和其他人想知道 oom-killer 是否可以配置为更早介入:reddit r/linux、superuser.com、unix.stackexchange.com。
事实证明,不,不能。至少使用内核中的 oom-killer。然而,在用户空间,我们可以做任何我们想做的事情。
Earlyoom 希望简单而可靠。它是用纯 C 语言编写的,没有依赖关系。广泛的测试套件(单元测试和集成测试)是用 Go 编写的。
Earlyoom 每秒最多检查 10 次可用内存和可用交换空间(如果有大量可用内存,则频率会降低)。默认情况下,如果两者都低于 10%,它将杀死最大的进程(最高的oom_score
)。百分比值可通过命令行参数进行配置。
在下面的free -m
输出中,可用内存为 2170 MiB,可用交换空间为 231 MiB。
total used free shared buff/cache available
Mem: 7842 4523 137 841 3182 2170
Swap: 1023 792 231
为什么检查“可用”内存而不是“空闲”内存?在一个健康的 Linux 系统上,“空闲”内存应该接近于零,因为 Linux 使用所有可用的物理内存来缓存磁盘访问。当内存需要用于其他用途时,可以随时删除这些缓存。
“可用”内存说明了这一点。它汇总了所有未使用或可以立即释放的内存。
请注意,您需要最新版本的free
版本和 Linux 内核 3.14+ 才能看到“可用”列。如果您有最新的内核,但free
版本较旧,则可以从grep MemAvailable /proc/meminfo
获取值。
当你的可用内存和空闲交换区都低于用户空间进程可用总内存(=total-shared)的 10% 时,它将向内核认为使用最多内存的进程发送SIGTERM
信号( /proc/*/oom_score
)。
Earlyoom 不使用echo f > /proc/sysrq-trigger
因为:
在某些内核版本中(在 v4.0.5 上测试),手动触发内核 oom Killer 根本不起作用。也就是说,它可能只会释放一些图形内存(将立即再次分配),而不会真正杀死任何进程。在这里您可以看到它在我的机器(英特尔集成显卡)上的样子。
此问题已在 Linux v5.17 中修复(提交 f530243a)。
就像 Linux 内核一样,earlyoom 通过读取/proc/*/oom_score
来找到它的受害者。
大约2 MiB
( VmRSS
),尽管只有220 kiB
是私有内存 ( RssAnon
)。其余的是与其他进程共享的 libc 库 ( RssFile
)。使用mlockall()
锁定所有内存,以确保 Earlyoom 在内存不足的情况下不会减慢速度。
自己编译很容易:
git clone https://github.com/rfjakob/earlyoom.git
cd earlyoom
make
可选:运行集成自测试:
make test
通过将earlyoom注册为服务来自动启动earlyoom:
sudo make install # systemd
sudo make install-initscript # non-systemd
请注意,对于禁用 SELinux 的系统(Ubuntu 19.04、Debian 9 ...),可以安全地忽略报告设置上下文失败的 chcon 警告。
对于 Debian 10+ 和 Ubuntu 18.04+,有一个 Debian 软件包:
sudo apt install earlyoom
对于带有 EPEL 的 Fedora 和 RHEL 8,有一个 Fedora 软件包:
sudo dnf install earlyoom
sudo systemctl enable --now earlyoom
对于 Arch Linux,有一个 Arch Linux 软件包:
sudo pacman -S earlyoom
sudo systemctl enable --now earlyoom
其他发行版中的可用性:请参阅repology 页面。
只需启动刚刚编译的可执行文件:
./earlyoom
它会告诉您有多少内存和交换空间,最小值是多少,有多少内存可用以及有多少交换空间是可用的。
./earlyoom
eearlyoom v1.8
mem total: 23890 MiB, user mem total: 21701 MiB, swap total: 8191 MiB
sending SIGTERM when mem avail <= 10.00% and swap free <= 10.00%,
SIGKILL when mem avail <= 5.00% and swap free <= 5.00%
mem avail: 20012 of 21701 MiB (92.22%), swap free: 5251 of 8191 MiB (64.11%)
mem avail: 20031 of 21721 MiB (92.22%), swap free: 5251 of 8191 MiB (64.11%)
mem avail: 20033 of 21723 MiB (92.22%), swap free: 5251 of 8191 MiB (64.11%)
[...]
如果该值降至最小值以下,进程将被终止,直到再次高于最小值。每个操作都会记录到 stderr。如果您将 Earlyoom 作为 systemd 服务运行,则可以使用以下命令查看最后 10 行
systemctl status earlyoom
为了查看earlyoom
实际效果,请创建/模拟内存泄漏并让earlyoom
执行其操作:
tail /dev/zero
如果您在进程被earlyoom
终止后需要任何进一步的操作(例如发送电子邮件),您可以通过以下方式解析日志:
sudo journalctl -u earlyoom | grep sending
上述测试命令( tail /dev/zero
)的示例输出将如下所示:
Feb 20 10:59:34 debian earlyoom[10231]: sending SIGTERM to process 7378 uid 1000 "tail": oom_score 156, VmRSS 4962 MiB
对于旧版本的
earlyoom
,请使用:sudo journalctl -u earlyoom | grep -iE "(sending|killing)"
从 1.6 版本开始,earlyoom 可以通过系统 d-bus 发送有关终止进程的通知。通过-n
来启用它们。
要实际在 GUI 会话中查看通知,您需要以用户身份运行 systembus-notify。
此外,earlyoom 可以为每个被杀死的进程执行一个脚本,通过EARLYOOM_PID
、 EARLYOOM_UID
和EARLYOOM_NAME
环境变量提供有关进程的信息。通过-N /path/to/script
来启用。
警告:在 dryrun 模式下,脚本将快速连续执行,确保您实施了某种速率限制。
命令行标志--prefer
指定优先杀死进程;同样, --avoid
指定避免杀死的进程。有关详细信息,请参阅 https://github.com/rfjakob/earlyoom/blob/master/MANPAGE.md#--prefer-regex。
如果您将 Earlyoom 作为系统服务运行(通过 systemd 或 init.d),则可以通过/etc/default/earlyoom
中提供的文件调整其配置。该文件已在注释中包含一些示例,您可以使用它们根据支持的命令行选项构建自己的配置集,例如:
EARLYOOM_ARGS="-m 5 -r 60 --avoid '(^|/)(init|Xorg|ssh)$' --prefer '(^|/)(java|chromium)$'"
调整文件后,只需重新启动服务即可应用更改。例如,对于 systemd:
systemctl restart earlyoom
请注意,此配置文件对 systemd/init.d 之外的 Earlyoom 实例没有影响。
earlyoom v1.8
Usage: ./earlyoom [OPTION]...
-m PERCENT[,KILL_PERCENT] set available memory minimum to PERCENT of total
(default 10 %).
earlyoom sends SIGTERM once below PERCENT, then
SIGKILL once below KILL_PERCENT (default PERCENT/2).
-s PERCENT[,KILL_PERCENT] set free swap minimum to PERCENT of total (default
10 %).
Note: both memory and swap must be below minimum for
earlyoom to act.
-M SIZE[,KILL_SIZE] set available memory minimum to SIZE KiB
-S SIZE[,KILL_SIZE] set free swap minimum to SIZE KiB
-n enable d-bus notifications
-N /PATH/TO/SCRIPT call script after oom kill
-g kill all processes within a process group
-d, --debug enable debugging messages
-v print version information and exit
-r INTERVAL memory report interval in seconds (default 1), set
to 0 to disable completely
-p set niceness of earlyoom to -20 and oom_score_adj to
-100
--ignore-root-user do not kill processes owned by root
--sort-by-rss find process with the largest rss (default oom_score)
--prefer REGEX prefer to kill processes matching REGEX
--avoid REGEX avoid killing processes matching REGEX
--ignore REGEX ignore processes matching REGEX
--dryrun dry run (do not kill any processes)
--syslog use syslog instead of std streams
-h, --help this help text
有关详细信息,请参阅手册页。
欢迎通过 github 提交错误报告和拉取请求。特别是我很高兴接受
v1.8.2, 2024-05-07
earlyoom.service
systemd 单元文件process_mrelease
添加到允许的系统调用(提交)IPAddressDeny
语法(提交)-p
(提交)v1.8.1, 2024-04-17
v1.8, 2024-04-15
user mem total
/ meminfo_t.UserMemTotal
并根据它计算 MemAvailablePercent (提交,手册页中的更多信息)process_mrelease
(#266)NO_COLOR
(https://no-color.org/)--sort-by-rss
,谢谢@RanHuang!这将选择一个进程来杀死 acc。使用最大的 RSS 而不是最大的 oom_score。v1.7, 2022-03-05
-N
标志以在每次进程被终止时运行脚本(提交,手册页部分)-g
标志来终止整个进程组 (#247)-i
标志(为了兼容性而忽略),它在 Linux 内核 5.9+ 上无法正常工作(#234)v1.6.2, 2020-10-14
1.6.1, 2020-07-07
1.6, 2020-04-11
dbus-send
/ systembus-notify 替换旧的notify-send
GUI 通知逻辑 (#183)-n
/ -N
现在启用新逻辑/proc
(问题 #184)v1.5, 2020-03-22
-p
: 将 oom_score_adj 设置为-100
而不是-1000
(#170)-M
和-m
以及-S
和-s
。将使用较低的值(转换为百分比)。earlyoom.default
中的内存报告间隔设置为1小时而不是1分钟(#177)v1.4, 2020-03-01
uid
make test
)cppcheck
make bench
)earlyoom.service
中的 root 权限v1.3.1, 2020-02-27
v1.3, 2019-05-26
v1.2, 2018-10-28
-k
,现在为了兼容性而忽略)(问题#80)v1.1, 2018-07-07
-h
之外还接受--help
-S
修复可能被零除的情况(提交)v1.0, 2018-01-28
--prefer
和--avoid
选项 (@TomJohnZ)-n
和-N
v0.12:添加-M
和-S
选项(@nailgun);添加手册页,参数化 Makefile (@yangfl)
v0.11:修复 get_entry_fatal 中未定义的行为(缺少返回、提交)
v0.10:允许覆盖Makefile的VERSION变量以使打包更容易,添加-v
命令行选项
v0.9:如果所有进程的oom_score为0,则使用VmRss查找受害者
v0.8:如果内核不提供 MemAvailable,则使用猜测
v0.7:通过 oom_score 而不是 VmRSS 选择受害者,添加选项-i
和-d
v0.6: 添加命令行选项-m
, -s
, -k
v0.5:添加交换支持
v0.4:添加 SysV 初始化脚本(感谢 @joeytwiddle),使用/proc/meminfo
中的新MemAvailable
(需要 Linux 3.14+,提交)
v0.2:添加systemd单元文件
v0.1:初始版本