我正在运行一个 shell 脚本,其中包含命令来连续运行多个内存密集型程序 (2-5 GB)。当我回去检查脚本的进度时,我惊讶地发现我的一些进程是Killed
,正如我的终端向我报告的那样。在后来启动的程序之前,有几个程序已经相继完成Killed
,但是之后的所有程序都因分段错误而失败(这可能是也可能不是由于我的代码中的错误所致,请继续阅读)。
我查看了我正在使用的特定集群的使用历史记录,发现有人开始同时运行多个内存密集型进程,这样做耗尽了集群可用的实际内存(甚至可能是交换空间)。据我所知,这些内存密集型进程大约在我的程序开始出现问题的同时开始运行。
Linux 有可能在内存不足时杀死我的程序吗?我后来遇到的分段错误是否有可能是由于缺乏可用于运行我的程序的内存(而不是我的代码中的错误)?
答案1
它可以。
在 Linux 中您可能会遇到两种不同的内存不足情况。您遇到的情况取决于sysctl vm.overcommit_memory
( /proc/sys/vm/overcommit_memory
)的值
简介:
内核可以执行所谓的“内存过量使用”。这是当内核为程序分配的内存多于系统中实际存在的内存时。这样做是希望程序实际上不会使用它们分配的所有内存,因为这是很常见的情况。
过量使用内存 = 2
当overcommit_memory
设置为时2
,内核根本不执行任何过量使用。相反,当为程序分配内存时,可以保证访问该内存。如果系统没有足够的可用内存来满足分配请求,内核将返回请求失败。由程序来优雅地处理这种情况。如果它在真正失败时不检查分配是否成功,应用程序通常会遇到段错误。
在出现段错误的情况下,您应该在以下输出中找到如下行dmesg
:
[1962.987529] myapp[3303]: segfault at 0 ip 00400559 sp 5bc7b1b0 error 6 in myapp[400000+1000]
这at 0
意味着应用程序尝试访问未初始化的指针,这可能是内存分配调用失败的结果(但这不是唯一的方法)。
过度使用内存 = 0 和 1
当overcommit_memory
设置为0
或 时1
,启用过量使用,并且允许程序分配比实际可用的内存更多的内存。
然而,当一个程序想要使用它分配的内存,但内核发现它实际上没有足够的内存来满足它时,它需要取回一些内存。它首先尝试执行各种内存清理任务,例如刷新缓存,但如果这还不够,它将终止进程。该终止由 OOM-Killer 执行。 OOM-Killer 会查看系统,了解哪些程序正在使用哪些内存、它们运行了多长时间、谁在运行它们以及许多其他因素来确定哪个程序被杀死。
进程被终止后,它正在使用的内存将被释放,并且刚刚导致内存不足情况的程序现在拥有它所需的内存。
然而,即使在这种模式下,程序仍然可能被拒绝分配请求。当overcommit_memory
is时0
,内核会尝试最佳猜测何时应该开始拒绝分配请求。当它设置为 时1
,我不确定它使用什么确定来确定何时应拒绝请求,但它可以拒绝非常大的请求。
您可以通过查看 的输出dmesg
并查找如下消息来查看是否涉及 OOM-Killer:
[11686.043641] Out of memory: Kill process 2603 (flasherav) score 761 or sacrifice child
[11686.043647] Killed process 2603 (flasherav) total-vm:1498536kB, anon-rss:721784kB, file-rss:4228kB
答案2
事实是,无论您以哪种方式看待它 - 无论您的进程是由于系统的内存管理器还是其他原因而阻塞 - 它都是仍然一个错误。您刚刚在内存中处理的所有数据发生了什么?它应该被保存。
虽然overcommit_memory=
这是配置 Linux OOM 管理的最通用方法,但它也可以按进程进行调整,例如:
echo [-+][n] >/proc/$pid/oom_adj
在上面使用-17
将从内存不足管理中排除进程。一般来说可能不是一个好主意,但如果你正在寻找错误,那么这样做可能是值得的 - 特别是如果你想知道它是否是 OOM或者你的代码。积极增加该数字将使进程更有可能在 OOM 事件中被终止,这可以使您能够更好地增强代码在低内存情况下的弹性,并确保您在必要时优雅退出。
您可以检查每个进程的 OOM 处理程序的当前设置,例如:
cat /proc/$pid/oom_score
否则你可能会自杀:
sysctl vm.panic_on_oom=1
sysctl kernel.panic=X
这将使计算机在内存不足的情况下重新启动。您将X
上述设置为您希望计算机在内核崩溃后重新启动之前停止的秒数。去野外。
如果出于某种原因,你决定喜欢它,就让它持久化:
echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf