c--*_*c-- 9 linux swap linux-kernel out-of-memory
我正在使用 Linux 5.15 和 Ubuntu 22.04。
我有一个使用大量内存的进程。它需要的内存比我机器上的 RAM 还要多。我第一次运行它时,它被 OOM Killer 杀死了。我的理解是:系统内存不足,OOM Killer 被触发,我的进程被杀死。这是有道理的。我也确信这就是发生的事情:我看了一下dmesg
,一切都在那里。
所以我添加了一些交换空间。我不介意这个过程是否需要很长时间才能运行:我不会经常运行它。
我再次运行该过程。这次比第一次跑的时间更长。整个系统变得非常滞后,系统在进行大量交换时就会出现这种情况。它似乎起作用了……然后就死了。不仅进程死了,它的父进程 shell 进程也死了,它的父进程 Tmux 进程、Tmux 进程的父进程 shell 进程,甚至它的父 GNOME 终端进程也死了!但随后谋杀过程停止了:不再有父母死亡。
起初,我以为 OOM Killer 再次被触发——尽管仍有大量交换空间可用——并且它选择终止 GNOME 终端进程。但我查了dmesg
一下,journalctl -k
并没有什么新的东西。没有任何迹象表明 OOM Killer 已被触发。
那么,第一个问题:是否有任何情况可以触发 OOM Killer,而不将任何内容记录到内核环形缓冲区?
让我困惑的是,Linux 内核似乎已经开始交换,但不知何故它交换得不够……或者交换得不够快……或者其他什么。
所以我增加了vm.swappiness
。这确实不应该影响系统稳定性:它只是一个用于性能优化的旋钮。即使vm.swappiness
设置为0
内核,当区域中的可用内存降至临界阈值以下时,内核仍应开始交换。
但似乎它已经开始交换,但交换得还不够……所以我增加了vm.swappiness
鼓励100
它交换更多一点。
然后我再次运行该过程。整个系统变得非常滞后,系统在进行大量交换时就会这样做......直到进程成功运行完成。
那么,第二个问题:为什么内核不使用可用的交换空间,即使空闲内存已降至临界阈值以下并且肯定有足够的可用交换空间?为什么改变会vm.swappiness
带来改变?
更新:
进一步的测试表明该设置vm.swappiness
不是一个可靠的解决方案。即使vm.swappiness
set to ,我也遇到过一些失败100
。它可能会提高该过程成功完成的机会,但我不确定。
在完全使用可用交换空间之前发生 OOM 事件有多种原因,并且 OOM 事件可能会触发 OOM-killer 线程或更糟糕的\xe2\x80\xa6 令人讨厌的信号:
\nA/ 关于内存分配和 OOM 事件的一般性
\n因为内核开发人员知道很多程序malloc()大量内存 \xe2\x80\x9c以防万一\xe2\x80\x9d 和 don\xe2\x80 \x99 不会使用其中的大部分,并且至少可能静态地期望系统上运行的所有进程不会同时需要它们请求的内存,内核实际上并不在 malloc 处保留内存(或朋友)点。
\n它将等待第一次对内存的写访问(这必然会导致页面错误)来进行真正的映射。
\n如果此时没有立即可用的内存,内核将等待更好的日子 (1),如果这些更好的日子来得不够快,将触发 OOM 事件。\nOOM 事件,取决于某些情况sysctl 设置 (panic_on_oom),将触发 OOM-killer 或生成内核恐慌。
B/ 为什么无论交换区中有多少可用空间,都可能发生 OOM 事件(2)
\nmlockall()
(6) cat /proc/meminfo
将报告为其目的而保留的内存量。C/ 为什么当内存压力较高时线程可以终止,而 OOM-killer 不会记录任何内容。(7)
\nmalloc
发布时做出。尽管内核默认采用“乐观策略”,但内核拒绝保留请求的情况总是可能发生,从而向malloc()
调用线程返回 NULL 指针。1:嗯,实际上毫秒更好,因为它最多会检查六次,中间有几纳秒的等待时间。请注意,这些数字属于我对现在旧内核的记忆,从那以后它们可能已经改变。
\n2:请注意,严格来说,Linux 不进行交换,因为交换是指将整个进程地址空间转移到磁盘。Linux 实际上实现了分页,因为它实际上传输单个页面。然而,使用交换\xe2\x80\xa6的文档和讨论就这样吧。
\n3: “间接”,因为较早开始交换只是该设置的副作用,该设置主要是为了告诉您偏好的文件系统缓存与进程页面。
\n由于文件系统的 IO 成本很高,Linux 将使用尽可能多的物理内存来进行缓存。
\nswappiness 的值越高,系统在进程启动时交换进程页面的积极性就越大,这会顺便增加在内存压力下可快速回收的缓存页面数量。
4:顺便说一句,这也解释了您的问题的反面:为什么系统在有大量可用的可用 RAM 的情况下进行交换?
\n5 :虽然我们可以阅读主要机构(RHEL、ORACLE\xe2\x80\xa6)建议将交换设置为严格的最小值\xe2\x80\xa6(并购买更多 RAM\xe2\x80\xa6)Morton(领先的内核) dev) 强烈建议值为 100。 \n随着zswap
等技术的出现,交换成本可能比文件系统 IO 更便宜,所以 swappiness 的值大于 100 甚至不会是荒谬的。
6:
\n\n\nRun Code Online (Sandbox Code Playgroud)\nmlockall() locks all pages mapped into the address space of the\n calling process. This includes the pages of the code, data, and\n stack segment, as well as shared libraries, user space kernel\n data, shared memory, and memory-mapped files. All mapped pages\n are guaranteed to be resident in RAM when the call returns\n successfully; the pages are guaranteed to stay in RAM until later\n unlocked.\n
7:请记住,即使启动了,OOM-killer 也相当\xe2\x80\xa6 懒惰,更喜欢让讨厌的任务自行终止。因此,如果罪魁祸首\xe2\x80\xa6 的信号正在等待,OOM-killer 将等待其采取行动\xe2\x80\xa6,以防万一\xe2\x80\xa6
\n首先,我要感谢MC68020花时间为我研究这个问题。碰巧的是,他们的答案并不包括这种情况下真正发生的事情 - 但他们无论如何都得到了赏金,因为这是一个很好的答案,并且对未来有帮助的参考。
我还要感谢Philip Couling的回答,虽然也不完全正确,但为我指明了正确的方向。
问题原来是systemd-oomd。
该问题及其解决方案描述如下:How do I disable the systemd OOM processkiller in Ubuntu 22.04?
简而言之:
systemctl disable --now systemd-oomd
systemctl mask systemd-oomd
Run Code Online (Sandbox Code Playgroud)
现在我每次都可以可靠地运行我的进程来完成,而无需某些 systemd 服务在没有警告的情况下杀死整个进程树。
归档时间: |
|
查看次数: |
1638 次 |
最近记录: |