Linux 是否会在不询问我内存是否不足的情况下开始杀死我的进程?

Neu*_*tar 75 linux kill memory segmentation-fault

我正在运行一个带有命令的 shell 脚本来连续运行几个内存密集型程序(2-5 GB)。当我回去检查我的脚本的进度时,我惊讶地发现我的一些进程是Killed,正如我的终端向我报告的那样。在后来Killed启动的程序之前已经连续完成了几个程序,但是之后的所有程序都因分段错误而失败(这可能是由于我的代码中的错误,也可能不是由于我的代码中的错误,请继续阅读)。

我查看了我正在使用的特定集群的使用历史记录,发现有人开始同时运行多个内存密集型进程,这样做耗尽了集群可用的实际内存(甚至可能是交换空间)。尽我所能,这些内存密集型进程在我的程序出现问题的同时开始运行。

一旦开始耗尽内存,Linux 是否有可能杀死我的程序?我后来遇到的分段错误是否可能是由于缺少可用于运行我的程序的内存(而不是我的代码中的错误)?

phe*_*mer 82

它可以。

在 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]
Run Code Online (Sandbox Code Playgroud)

at 0意味着应用程序试图访问未初始化的指针,这可能是内存分配调用失败的结果(但这不是唯一的方法)。

overcommit_memory = 0 和 1

overcommit_memory设置为0or 时1,过量使用被启用,并且允许程序分配比实际可用更多的内存。

然而,当一个程序想要使用它分配的内存时,内核发现它实际上没有足够的内存来满足它,它需要取回一些内存。它首先尝试执行各种内存清理任务,例如刷新缓存,但如果这还不够,它将终止进程。该终止由 OOM-Killer 执行。OOM-Killer 查看系统以查看哪些程序正在使用哪些内存、它们运行了多长时间、谁在运行它们,以及许多其他因素来确定哪个程序被杀死。

进程被杀死后,它使用的内存被释放,刚刚导致内存不足情况的程序现在有了它需要的内存。

然而,即使在这种模式下,程序仍然可以拒绝分配请求。当overcommit_memoryis 时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
Run Code Online (Sandbox Code Playgroud)


mik*_*erv 16

事实是,无论您以何种方式看待它 - 无论您的进程是由于系统的内存管理器还是由于其他原因而被阻塞 - 它仍然是一个错误。您刚刚在内存中处理的所有数据发生了什么变化?它应该被保存了。

虽然overcommit_memory=是配置 Linux OOM 管理的最通用方法,但它也可以按进程进行调整,例如:

echo [-+][n] >/proc/$pid/oom_adj
Run Code Online (Sandbox Code Playgroud)

-17在上面使用将排除内存不足管理的进程。通常可能不是一个好主意,但如果您正在寻找错误,那么这样做可能是值得的 - 特别是如果您想知道它是 OOM还是您的代码。积极增加数字将使进程更有可能在 OOM 事件中被终止,这可以使您在低内存情况下更好地支持代码的弹性,并确保您在必要时优雅地退出。

您可以检查每个进程的 OOM 处理程序的当前设置,例如:

cat /proc/$pid/oom_score 
Run Code Online (Sandbox Code Playgroud)

否则你可能会自杀:

sysctl vm.panic_on_oom=1
sysctl kernel.panic=X
Run Code Online (Sandbox Code Playgroud)

这将使计算机在内存不足的情况下重新启动。您将X上述设置为您希望计算机在内核崩溃后在重新启动之前停止的秒数。去野外。

如果出于某种原因,你决定喜欢它,让它持久化:

echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf
Run Code Online (Sandbox Code Playgroud)

  • @Joshua - 我非常怀疑有人会喜欢它 - 它甚至违反了阿西莫夫的机器人定律。另一方面,正如我提到的,您也可以以另一种方式配置每个进程的 OOM。也就是说,您可以根据自己定义的每个流程的规则集进行个人分类。这种事情听起来在共享集群场景中可能特别有用。 (3认同)