使用 cgroups v1,可以监听有关内存压力的事件。根据文档, 需要
- 创建一个新的
eventfd
- 开放
memory.pressure_level
阅读 - 开放
cgroup.event_control
写作 - 写入
{eventfd} {pressure_level_fd} {level}
(其中level
、low
或medium
)critical
至event_control
- 等待直到从 eventfd 读取返回 8 个字节
当对即将耗尽内存的程序执行此操作时,您将收到一长串low
事件,然后是一些medium
和critical
,最后 OOM 杀手将运行。如果你想说服自己这一点,我准备了一份Rust 的小例子,您可以使用 执行它cargo build --release --examples && sudo target/release/examples/cv1
。
对于 cgroups v2 (文档),类似的事件可以通过
- 设置 inotify 手表
memory.events.local
- 完全读取和解析文件,在收到每个事件后比较数字
当在 cgroup 中设置内存限制时,这有效(即使没有 root,与 v1 不同),并且您通常会收到至少一些 inotify 事件,其中 或 会high
增加max
。 (再次强调,如果你想说服自己相信这一点,请systemd-run --same-dir --pty --user -p MemoryMax=1G cargo run --example cv2
按照上述要点进行操作。)
但是,当没有设置内存限制,或者限制高于可用内存时,进程将被终止,而不会收到事件。查看memory.pressure
显示强劲的增长,因此内核在调用 OOM 杀手之前肯定知道发生了某些事情。有没有办法让它告诉我们,像 cgroups v1 这样的良好行为会提前发出很多警告?
- 它们很旧,问题/答案只考虑 cgroups v1
- 我希望在 oom Killer 激活之前被触发,这样“生成高 oom_score_adj 金丝雀进程”的黑客就不会出现了。
答案1
读完后文档更仔细一点,我找到了答案。总而言之,您可以通过写入some 50000 2000000\0
fd /proc/pressure/memory
,然后轮询 fd 的PRI
事件来观察内存压力。
我没有将其标记为已接受,因为我对此不满意:
- 基于 cgroups 的变体 (at
$CGROUP_FS/$GROUP/memory.pressure
) 仅适用于 root - 如果您使用全局变体 at/proc/pressure/
,即使您的进程仍然有大量可用内存,您也可能会收到事件。 - 非 root 用户的最小间隔是 2 秒 - 在没有交换的系统上,这意味着您可能会在第一个事件发生之前被 OOM 杀死。