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


66

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

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

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


2
分配内存时,是否有一条语句检查内存是否已成功分配?这应该提供一个线索,说明代码中是否存在错误,或者是否是由于系统内存不足所致。
unxnut 2014年

Answers:


72

它可以。

在Linux中,您可能会遇到两种不同的内存不足情况。您遇到的取决于sysctl vm.overcommit_memory/proc/sys/vm/overcommit_memory)的值

简介:
内核可以执行所谓的“内存过量使用”。这是内核为程序分配的内存大于系统中实际内存的时间。这样做是希望程序不会真正使用它们分配的所有内存,因为这是很常见的情况。

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意味着应用程序尝试访问未初始化的指针,这可能是内存分配调用失败的结果(但这不是唯一的方法)。

overcommit_memory = 0和1

overcommit_memory设置为0或时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

因此,似乎这两种情况都发生在我身上。
NeutronStar 2014年

@Joshua我刚刚更新了答案。我忘了提,当你仍然可以得到分配失败overcommit_memory被设置为0或2
帕特里克

我认为编辑指向驯化OOM杀手的链接可能是值得的。
0xC0000022L 2014年

@ 0xC0000022L谢谢,那是一篇不错的文章(尽管有些过时了)。我不想对控制OOM杀手进行任何说明,因为这不是问题的一部分(而且这不是一个简短的主题),我们在此还有很多其他问题。
2014年

1
@mikeserv我不是说OOM杀手的行为与控制它无关。问题是Linux是否会杀死他的程序。首先要如何防止linux这样做,需要确定确实是linux在这样做。而且,如果overcommit_memory=2,甚至都没有启用OOM杀手,则控制它无关紧要。但是,一旦我们确定它是OOM杀手,它便成为另一个主题,这里包含许多其他问题和解答。
帕特里克

16

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

虽然这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

这是我正在使用的共享群集,我敢肯定其他用户在未经其同意的情况下不希望重新启动它。
NeutronStar 2014年

3
@Joshua-我非常怀疑有人会喜欢它-它甚至违反了阿西莫夫的机器人法则。另一方面,正如我提到的,您也可以使用其他方法为每个进程配置OOM。也就是说,您可以根据每个过程自己定义的规则集进行个人分类。这种事情听起来在共享集群场景中可能特别有用。
mikeserv 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.