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
)。
nohang,一个类似 Earlyoom 的项目,用 Python 编写,并具有附加功能和配置选项。
facebooks 的压力失速信息 (psi) 内核补丁和随附的 oomd 用户空间帮助程序。这些补丁已合并到 Linux 4.20 中。
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 克隆 https://github.com/rfjakob/earlyoom.gitcd Earlyoom 制作
可选:运行集成自测试:
进行测试
通过将earlyoom注册为服务来自动启动earlyoom:
sudo make install # systemdsudo make install-initscript # 非systemd
请注意,对于禁用 SELinux 的系统(Ubuntu 19.04、Debian 9 ...),可以安全地忽略报告设置上下文失败的 chcon 警告。
对于 Debian 10+ 和 Ubuntu 18.04+,有一个 Debian 软件包:
sudo apt install Earlyoom
对于带有 EPEL 的 Fedora 和 RHEL 8,有一个 Fedora 软件包:
须藤 dnf 安装 Earlyoom sudo systemctl启用--现在earlyoom
对于 Arch Linux,有一个 Arch Linux 软件包:
sudo pacman -S Earlyoom sudo systemctl启用--现在earlyoom
其他发行版中的可用性:请参阅repology 页面。
只需启动刚刚编译的可执行文件:
./清晨
它会告诉您有多少内存和交换空间,最小值是多少,有多少内存可用以及有多少交换空间是可用的。
./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状态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 重新启动 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 提交错误报告和拉取请求。特别是我很高兴接受
使用案例报告和反馈
我们不使用 procps/libproc2,因为 procps_pids_select() 由于某种原因总是解析 /proc/$pid/status。这个比较贵,我们不需要。
v1.8.2, 2024-05-07
将process_mrelease
添加到允许的系统调用(提交)
修复IPAddressDeny
语法(提交)
允许-p
(提交)
修复了earlyoom.service
systemd 单元文件
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。
Gitlab CI 测试套件现在也可以在 Amazon Linux 2 和 Oracle Linux 7 上运行。
v1.7, 2022-03-05
添加-N
标志以在每次进程被终止时运行脚本(提交,手册页部分)
添加-g
标志来终止整个进程组 (#247)
删除-i
标志(为了兼容性而忽略),它在 Linux 内核 5.9+ 上无法正常工作(#234)
强化:启动时删除环境功能 (#234)
v1.6.2, 2020-10-14
在杀死受害者之前仔细检查内存情况(提交)
永远不要终止我们自己(#205)
/proc/meminfo 转换错误时转储缓冲区 (#214)
1.6.1, 2020-07-07
清理 dbus-send 僵尸进程 (#200)
跳过 oom_score_adj=-1000 (210) 的进程
1.6, 2020-04-11
-n
/ -N
现在启用新逻辑
您需要在 GUI 会话中运行 systembus-notify 以获取工作通知
用dbus-send
/ systembus-notify 替换旧的notify-send
GUI 通知逻辑 (#183)
优雅地处理使用 hidepid 挂载的/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
尽可能使用块局部变量
引入 PATH_LEN 来替换几个硬编码的缓冲区长度
通过延迟加载进程属性使受害者选择逻辑速度提高 50%
除了 pid 和名称之外,还记录已终止进程的用户 ID uid
颜色调试日志为浅灰色
代码清理
展开测试套件( make test
)
可用时运行cppcheck
添加单元测试基准( make bench
)
删除 systemd 单元文件earlyoom.service
中的 root 权限
v1.3.1, 2020-02-27
修复具有大量 RAM 的系统上的虚假测试套件故障(问题 #156)
v1.3, 2019-05-26
如果 SIGTERM 限制 < SIGKILL 限制,则不要退出并出现致命错误
允许零 SIGKILL 限制
这解决了 Earlyoom 有时在一个进程就足够时杀死多个进程的问题(问题#121)
发送信号时等待进程实际退出
对 SIGTERM 和 SIGKILL 的接受限制更加自由(问题 #97)
重新格式化启动输出以明确 swap 和 mem 都必须 <= limit
添加notify_all_users.py帮助脚本
添加 CODE_OF_CONDUCT.md(贡献者契约 1.4)(#102)
修复日志输出中可能被截断的 UTF8 应用程序名称 (#110)
v1.2, 2018-10-28
实施自适应睡眠时间(=自适应轮询率)以进一步降低 CPU 使用率(问题 #61)
删除使用内核 oom-killer 的选项( -k
,现在为了兼容性而忽略)(问题#80)
优雅地处理 Earlyoom 启动后添加或删除交换的情况(第 62 期,提交)
实施分阶段终止:首先是 SIGTERM,然后是 SIGKILL,并具有可配置的限制(问题 #67)
v1.1, 2018-07-07
通过 GUI 通知修复可能的 shell 代码注入(提交)
如果无法终止任何进程,则仅休眠 1 秒而不是 10 秒(问题 #74)
在杀死之后发送 GUI 通知,而不是之前(问题 #73)
除了-h
之外还接受--help
修复日志和终止通知中错误的进程名称(提交 1、提交 2、问题 #52、问题 #65、问题 #194)
使用-S
修复可能被零除的情况(提交)
v1.0, 2018-01-28
添加--prefer
和--avoid
选项 (@TomJohnZ)
添加对 GUI 通知的支持,添加选项-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:初始版本