我的进程为什么会被终止?原因是什么?

803

我的应用程序在Linux上作为后台进程运行。它目前是在终端窗口中的命令行中启动。

最近,一个用户正在执行该应用程序,并且它神秘地死亡。终端上显示出如下文本:

已杀死

这种情况发生了两次。我问过一个不同的终端是否使用kill命令来终止该进程?没有。

在什么条件下,Linux会决定杀死我的进程?我相信shell显示"已杀死",因为进程在收到kill(9)信号后死亡。如果Linux发送kill信号,那么系统日志中应该有一条消息,解释为什么要杀死它吗?


44
Linux杀死了我的进程并将其记录在红帽Linux的/var/log/messages日志中。 - Dean Hiller
2
参见unix.stackexchange.com上的这个答案 - Richard
5
此事件涉及三个角色:(1) 进程,由于一些常见原因导致其占用过多内存并引发OOM条件; (2) 内核,在终止该进程时发送SIGKILL信号(信号9),并在某些系统日志(例如/var/log/messages)中记录此事实;(3) 该进程所在的shell,当从waitpid(2)函数的退出状态指示子进程死亡信号为9时,打印出“Killed”通知的进程。 - arielf
7
阅读@DeanHiller的回答后,我发现Ubuntu系统下的日志信息位于/var/log/syslog目录下。 - Dinei
13个回答

492

如果用户或系统管理员没有杀死程序,则可能是内核干的。内核只会在极端情况下,例如资源极度匮乏(如内存和交换空间耗尽)时才会终止进程。


41
如果内核杀死了进程,它会在某个日志中记录消息吗? - sbq
220
我刚刚写了一个程序,在一个无限循环中使用malloc分配内存。 当系统变慢时,终端上显示了“Killed”并终止了该进程。 文件/var/log/kern.log包含有关终止的大量信息。-感谢指点。 - sbq
10
几乎可以确定了。我在当助教时经常看到这种情况。许多学生会忘记释放他们的对象,应用程序最终会达到3GB的虚拟内存使用量。一旦达到这个点就会被强制终止。 - Herms
12
当“程序崩溃”时,那就是操作系统实际上杀死了该进程! - Bernd Jendrissek
104
使用 dmesg 命令查看内核日志:我发现我的 Python 进程由于极端虚拟内存消耗而被内核杀死。 - caneta
显示剩余9条评论

425

尝试:

dmesg -T| grep -E -i -B100 'killed process'

-B100 表示杀掉进程前的行数。

在 Mac OS 上不需要加 -T


6
FYI,从info egrep中可以得知:"egrep与grep -E相同。...直接使用egrep或fgrep已经过时了。" - Air
11
对于像“'killed process'”这样的简单模式,您可以只使用grep而不进行其他更改。对于更复杂的模式,您需要将例如egrep -i -B100 'foo|ba[rz]'替换为grep -E -i -B100 'foo|ba[rz]'。这个问题和答案提供了更多细节。 - Air
5
我建议使用dmesg -T命令,以获得可读的时间戳。 - gukoff
如果您只想在服务器上查看最近终止的进程列表,请尝试使用 dmesg -T| grep -E 'Killed process' - Meet Sinojia
请注意,dmesg命令只显示存储在内核环形缓冲区中的消息。如果您正在搜索OOM(内存不足)消息,它们有可能被覆盖,无法通过dmesg命令访问。您需要在其他位置进行搜索,如/var/log/kern.log/var/log/messages - caltuntas

198
这篇文章似乎是关于这个主题的好文章:Taming the OOM killer (1)。主要内容是Linux系统进行了过度提交内存。当进程请求更多空间时,Linux会给予它那些空间,即使该空间已被其他进程占用,因为Linux假设没有人实际使用他们所请求的所有内存。进程在实际使用内存时才获得其分配的内存的独占使用权,而不是在请求时。这使得分配快速,并可能允许您“欺骗”并分配比您实际拥有的更多内存。然而,一旦进程开始使用该内存,Linux可能会意识到在分配内存时太慷慨了,需要杀死一个进程来释放一些内存。将被杀死的进程基于得分,考虑运行时间(长时间运行的进程更安全),内存使用情况(贪婪的进程不太安全)以及几个其他因素,包括您可以调整的一个值,以使进程不太可能被杀死。在这篇文章中,所有这些都有更详细的描述。
编辑:这里还有[另一篇文章] (2) 很好地说明了进程选择的过程(并带有一些内核代码示例的注释)。这篇文章的伟大之处在于它包括一些关于各种badness()规则背后的推理的评论。

3
我非常喜欢这些文章链接。我建议任何对这个话题感兴趣的人都去阅读它们,特别是lwn文章下的评论。 - Jon Bringhurst
4
即使有其他进程声明了空间,Linux也会为其提供虚拟内存。但这并不完全符合虚拟内存的工作原理... - Mooing Duck
1
该文章相当古老 (2009年),并且文章中建议的所有功能都没有在主线中。 - Alexander Oh

64

首先让我解释一下 OOMKiller 是何时以及为什么会被激活的?

假设你有 512MB 的内存和 1GB 的交换空间,因此理论上,你的 CPU 可以访问总共 1.5GB 的虚拟内存。

现在,在 1.5GB 的总内存范围内,一段时间内一切都正常运行。但是突然(或逐渐)你的系统开始消耗更多的内存,并且它已经达到了总内存使用量约为 95% 的一个点。

现在,假设任何进程已从内核请求大块内存。内核检查可用内存并发现无法为进程分配更多内存。因此,它将尝试通过调用/触发 OOMKiller (http://linux-mm.org/OOM) 来释放一些内存。

OOMKiller 有自己的算法来为每个进程评分。通常使用更多内存的进程成为要被杀死的受害者。

我在哪里可以找到 OOMKiller 的日志?

通常在 /var/log 目录中。可以是 /var/log/kern.log 或 /var/log/dmesg

希望这可以帮助你。

一些典型的解决方案:

  1. 增加内存(而不是交换空间)
  2. 查找程序中的内存泄漏并修复它们
  3. 限制任何进程可以消耗的内存(例如,可以使用 JAVA_OPTS 限制 JVM 内存)
  4. 查看日志并谷歌 :)

25

这是Linux的内存不足管理器(OOM)。您的进程被选中是由于“糟糕度” - 最近性,常驻大小(使用的内存而非只是分配的内存)以及其他因素的综合。

sudo journalctl -xb

你会看到类似以下的消息:

Jul 20 11:05:00 someapp kernel: Mem-Info:
Jul 20 11:05:00 someapp kernel: Node 0 DMA per-cpu:
Jul 20 11:05:00 someapp kernel: CPU    0: hi:    0, btch:   1 usd:   0
Jul 20 11:05:00 someapp kernel: Node 0 DMA32 per-cpu:
Jul 20 11:05:00 someapp kernel: CPU    0: hi:  186, btch:  31 usd:  30
Jul 20 11:05:00 someapp kernel: active_anon:206043 inactive_anon:6347 isolated_anon:0
                                    active_file:722 inactive_file:4126 isolated_file:0
                                    unevictable:0 dirty:5 writeback:0 unstable:0
                                    free:12202 slab_reclaimable:3849 slab_unreclaimable:14574
                                    mapped:792 shmem:12802 pagetables:1651 bounce:0
                                    free_cma:0
Jul 20 11:05:00 someapp kernel: Node 0 DMA free:4576kB min:708kB low:884kB high:1060kB active_anon:10012kB inactive_anon:488kB active_file:4kB inactive_file:4kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present
Jul 20 11:05:00 someapp kernel: lowmem_reserve[]: 0 968 968 968
Jul 20 11:05:00 someapp kernel: Node 0 DMA32 free:44232kB min:44344kB low:55428kB high:66516kB active_anon:814160kB inactive_anon:24900kB active_file:2884kB inactive_file:16500kB unevictable:0kB isolated(anon):0kB isolated
Jul 20 11:05:00 someapp kernel: lowmem_reserve[]: 0 0 0 0
Jul 20 11:05:00 someapp kernel: Node 0 DMA: 17*4kB (UEM) 22*8kB (UEM) 15*16kB (UEM) 12*32kB (UEM) 8*64kB (E) 9*128kB (UEM) 2*256kB (UE) 3*512kB (UM) 0*1024kB 0*2048kB 0*4096kB = 4580kB
Jul 20 11:05:00 someapp kernel: Node 0 DMA32: 216*4kB (UE) 601*8kB (UE) 448*16kB (UE) 311*32kB (UEM) 135*64kB (UEM) 74*128kB (UEM) 5*256kB (EM) 0*512kB 0*1024kB 1*2048kB (R) 0*4096kB = 44232kB
Jul 20 11:05:00 someapp kernel: Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
Jul 20 11:05:00 someapp kernel: 17656 total pagecache pages
Jul 20 11:05:00 someapp kernel: 0 pages in swap cache
Jul 20 11:05:00 someapp kernel: Swap cache stats: add 0, delete 0, find 0/0
Jul 20 11:05:00 someapp kernel: Free swap  = 0kB
Jul 20 11:05:00 someapp kernel: Total swap = 0kB
Jul 20 11:05:00 someapp kernel: 262141 pages RAM
Jul 20 11:05:00 someapp kernel: 7645 pages reserved
Jul 20 11:05:00 someapp kernel: 264073 pages shared
Jul 20 11:05:00 someapp kernel: 240240 pages non-shared
Jul 20 11:05:00 someapp kernel: [ pid ]   uid  tgid total_vm      rss nr_ptes swapents oom_score_adj name
Jul 20 11:05:00 someapp kernel: [  241]     0   241    13581     1610      26        0             0 systemd-journal
Jul 20 11:05:00 someapp kernel: [  246]     0   246    10494      133      22        0         -1000 systemd-udevd
Jul 20 11:05:00 someapp kernel: [  264]     0   264    29174      121      26        0         -1000 auditd
Jul 20 11:05:00 someapp kernel: [  342]     0   342    94449      466      67        0             0 NetworkManager
Jul 20 11:05:00 someapp kernel: [  346]     0   346   137495     3125      88        0             0 tuned
Jul 20 11:05:00 someapp kernel: [  348]     0   348    79595      726      60        0             0 rsyslogd
Jul 20 11:05:00 someapp kernel: [  353]    70   353     6986       72      19        0             0 avahi-daemon
Jul 20 11:05:00 someapp kernel: [  362]    70   362     6986       58      18        0             0 avahi-daemon
Jul 20 11:05:00 someapp kernel: [  378]     0   378     1621       25       8        0             0 iprinit
Jul 20 11:05:00 someapp kernel: [  380]     0   380     1621       26       9        0             0 iprupdate
Jul 20 11:05:00 someapp kernel: [  384]    81   384     6676      142      18        0          -900 dbus-daemon
Jul 20 11:05:00 someapp kernel: [  385]     0   385     8671       83      21        0             0 systemd-logind
Jul 20 11:05:00 someapp kernel: [  386]     0   386    31573      153      15        0             0 crond
Jul 20 11:05:00 someapp kernel: [  391]   999   391   128531     2440      48        0             0 polkitd
Jul 20 11:05:00 someapp kernel: [  400]     0   400     9781       23       8        0             0 iprdump
Jul 20 11:05:00 someapp kernel: [  419]     0   419    27501       32      10        0             0 agetty
Jul 20 11:05:00 someapp kernel: [  855]     0   855    22883      258      43        0             0 master
Jul 20 11:05:00 someapp kernel: [  862]    89   862    22926      254      44        0             0 qmgr
Jul 20 11:05:00 someapp kernel: [23631]     0 23631    20698      211      43        0         -1000 sshd
Jul 20 11:05:00 someapp kernel: [12884]     0 12884    81885     3754      80        0             0 firewalld
Jul 20 11:05:00 someapp kernel: [18130]     0 18130    33359      291      65        0             0 sshd
Jul 20 11:05:00 someapp kernel: [18132]  1000 18132    33791      748      64        0             0 sshd
Jul 20 11:05:00 someapp kernel: [18133]  1000 18133    28867      122      13        0             0 bash
Jul 20 11:05:00 someapp kernel: [18428]    99 18428   208627    42909     151        0             0 node
Jul 20 11:05:00 someapp kernel: [18486]    89 18486    22909      250      46        0             0 pickup
Jul 20 11:05:00 someapp kernel: [18515]  1000 18515   352905   141851     470        0             0 npm
Jul 20 11:05:00 someapp kernel: [18520]     0 18520    33359      291      66        0             0 sshd
Jul 20 11:05:00 someapp kernel: [18522]  1000 18522    33359      294      64        0             0 sshd
Jul 20 11:05:00 someapp kernel: [18523]  1000 18523    28866      115      12        0             0 bash
Jul 20 11:05:00 someapp kernel: Out of memory: Kill process 18515 (npm) score 559 or sacrifice child
Jul 20 11:05:00 someapp kernel: Killed process 18515 (npm) total-vm:1411620kB, anon-rss:567404kB, file-rss:0kB

我该如何找出内存缺陷的数量? - TD1
1
@TD1 这取决于数据量的大小 - 通常你会有一个进程的堆快照(这取决于所使用的编程语言/虚拟机)。但答案可能是 - “赤字是无限的,因为你有内存泄漏” - 例如,你正在添加到你正在使用的数组中,它只会随着程序运行时间的增长而变得越来越大。 - mikemaccana
只是一个提示,如果你像这样添加grep:sudo journalctl -xb | grep "Killed process <process id>",它将仅显示有关你感兴趣的进程被杀死的行。 - user749127

17

正如dwc和Adam Jaskiewicz所说,罪魁祸首很可能是OOM Killer。不过,接下来的问题是:我该如何预防这种情况呢?

有几种方法:

  1. 如果可以的话,给您的系统增加更多的RAM(如果是VM,则很容易)。
  2. 确保OOM Killer选择不同的进程。
  3. 禁用OOM Killer。
  4. 选择一个未启用OOM Killer的Linux发行版。

我发现第二种方法特别容易实现:

/proc/<PID>/oom_score_adj 调整为 -1000 (这会自动将 oom_adj 设为 -17,将 oom_score 设为 0)。

请参见如何在Linux中创建OOM排除项了解更多信息。


9
对我而言,关键是内存条。我将内存从2GB升级到4GB,问题就解决了。现在的问题在于账单 :P - Gus
2
方法二:这篇文章很有用,但已经过时了。现在你应该将 /proc/<PID>/oom_score_adj 调整为 -1000(这会自动将 oom_adj 调整为 -17,将 oom_score 调整为 0,因此你的进程永远不会被杀掉)。 - maganap
@maganap 的评论非常好,由于这篇文章已经过时,我已将其添加到答案中。 - mikemaccana

13

像systemtap这样的工具(或跟踪器)可以监视内核信号传输逻辑并报告。例如,https://sourceware.org/systemtap/examples/process/sigmon.stp

# stap --example sigmon.stp -x 31994 SIGKILL
   SPID     SNAME            RPID  RNAME            SIGNUM SIGNAME
   5609     bash             31994 find             9      SIGKILL

该脚本中的筛选if块可根据需要进行调整,或者可以消除以跟踪系统范围的信号流量。可以通过收集回溯来进一步分离原因(向探针添加print_backtrace()和/或print_ubacktrace()用于内核和用户空间,分别)。


10

限制资源的PAM模块正是导致了你所描述的情况: 我的进程突然死亡并在控制台窗口上显示“Killed”字样,没有任何日志输出,无论是在syslog还是在kern.log中都没有。使用top程序帮助我发现,我的进程在使用CPU一分钟后就会被终止。


4
在lsf环境(交互式或其他方式)中,如果应用程序超过管理员在队列上设置的某些预设阈值或提交到队列的资源请求所需内存利用率,进程将被终止,以便其他用户不会受到潜在的失控影响。它并不总是在这样做时发送电子邮件,这取决于它的设置。
在这种情况下,一个解决方案是找到具有更大资源的队列或在提交时定义更大的资源要求。
您可能还想查阅man ulimit文档。
尽管我不记得ulimit会导致Killed,但自从我需要它以来已经有一段时间了。

3

在我的情况下,这是在Laravel队列工作者中发生的。系统日志没有提到任何杀死进程的信息,所以我进一步查看后发现,工作者基本上是因为一个作业超过了内存限制(默认设置为128M)而自行终止。

使用 --timeout=600--memory=1024 运行队列工作者可以解决我的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接