如何让 Linux OOM 终止程序不终止我的进程?

如何让 Linux OOM 终止程序不终止我的进程?

当物理内存不足但交换空间充足时,如何让 Linux OOM 终止程序不终止我的进程?

我已禁用 OOM 终止并使用 sysctl vm.overcommit_memory=2 进行过度提交。

VM 具有 3 GB 的完全可用的未碎片化交换空间,并且被 OOM 终止的进程的最大内存使用量小于 200MB。

我知道长期交换会对性能产生很大影响,但是我现在需要使用交换来在 valgrind 下进行功能测试,因为那里的内存需求要大得多。

Mar  7 02:43:11 myhost kernel: memcheck-amd64- invoked oom-killer: gfp_mask=0x24002c2, order=0, oom_score_adj=0
Mar  7 02:43:11 myhost kernel: memcheck-amd64- cpuset=/ mems_allowed=0
Mar  7 02:43:11 myhost kernel: CPU: 0 PID: 3841 Comm: memcheck-amd64- Not tainted 4.4.0-x86_64-linode63 #2
Mar  7 02:43:11 myhost kernel: Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.8.2-0-g33fbe13 by qemu-project.org 04/01/2014
Mar  7 02:43:11 myhost kernel: 0000000000000000 0000000000000000 ffffffff8158cbcc ffff880032d7bc18
Mar  7 02:43:11 myhost kernel: ffffffff811c6a55 00000015118e701d ffffffff81044a8d 00000000000003e2
Mar  7 02:43:11 myhost kernel: ffffffff8110f5a1 0000000000000000 00000000000003e2 ffffffff81cf15cc
Mar  7 02:43:11 myhost kernel: Call Trace:
Mar  7 02:43:11 myhost kernel: [<ffffffff8158cbcc>] ? dump_stack+0x40/0x50
Mar  7 02:43:11 myhost kernel: [<ffffffff811c6a55>] ? dump_header+0x59/0x1dd
Mar  7 02:43:11 myhost kernel: [<ffffffff81044a8d>] ? kvm_clock_read+0x1b/0x1d
Mar  7 02:43:11 myhost kernel: [<ffffffff8110f5a1>] ? __raw_callee_save___pv_queued_spin_unlock+0x11/0x1e
Mar  7 02:43:11 myhost kernel: [<ffffffff81183316>] ? oom_kill_process+0xc0/0x34f
Mar  7 02:43:11 myhost kernel: [<ffffffff811839b2>] ? out_of_memory+0x3bf/0x406
Mar  7 02:43:11 myhost kernel: [<ffffffff81187bbd>] ? __alloc_pages_nodemask+0x8ba/0x9d8
Mar  7 02:43:11 myhost kernel: [<ffffffff811b82e8>] ? alloc_pages_current+0xbc/0xe0
Mar  7 02:43:11 myhost kernel: [<ffffffff811b096c>] ? __vmalloc_node_range+0x12d/0x20a
Mar  7 02:43:11 myhost kernel: [<ffffffff811e0e62>] ? alloc_fdtable+0x6a/0xd8
Mar  7 02:43:11 myhost kernel: [<ffffffff811b0a83>] ? __vmalloc_node+0x3a/0x3f
Mar  7 02:43:11 myhost kernel: [<ffffffff811e0e62>] ? alloc_fdtable+0x6a/0xd8
Mar  7 02:43:11 myhost kernel: [<ffffffff811b0ab0>] ? vmalloc+0x28/0x2a
Mar  7 02:43:11 myhost kernel: [<ffffffff811e0e62>] ? alloc_fdtable+0x6a/0xd8
Mar  7 02:43:11 myhost kernel: [<ffffffff811e1338>] ? dup_fd+0x103/0x1f0
Mar  7 02:43:11 myhost kernel: [<ffffffff810dd143>] ? copy_process+0x5aa/0x160d
Mar  7 02:43:11 myhost kernel: [<ffffffff8110f5a1>] ? __raw_callee_save___pv_queued_spin_unlock+0x11/0x1e
Mar  7 02:43:11 myhost kernel: [<ffffffff810de2fc>] ? _do_fork+0x7d/0x291
Mar  7 02:43:11 myhost kernel: [<ffffffff810ea186>] ? __set_current_blocked+0x47/0x52
Mar  7 02:43:11 myhost kernel: [<ffffffff810ea1f2>] ? sigprocmask+0x61/0x6a
Mar  7 02:43:11 myhost kernel: [<ffffffff81998eae>] ? entry_SYSCALL_64_fastpath+0x12/0x71
Mar  7 02:43:11 myhost kernel: Mem-Info:
Mar  7 02:43:11 myhost kernel: active_anon:15 inactive_anon:18 isolated_anon:0
Mar  7 02:43:11 myhost kernel: active_file:7 inactive_file:8 isolated_file:0
Mar  7 02:43:11 myhost kernel: unevictable:0 dirty:3 writeback:26 unstable:0
Mar  7 02:43:11 myhost kernel: slab_reclaimable:1798 slab_unreclaimable:3674
Mar  7 02:43:11 myhost kernel: mapped:8 shmem:1 pagetables:752 bounce:0
Mar  7 02:43:11 myhost kernel: free:1973 free_pcp:0 free_cma:0
Mar  7 02:43:11 myhost kernel: Node 0 DMA free:3944kB min:60kB low:72kB high:88kB active_anon:0kB inactive_anon:0kB active_file:28kB inactive_file:32kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15992kB managed:15908kB
 mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:72kB slab_unreclaimable:236kB kernel_stack:48kB pagetables:60kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:36
0 all_unreclaimable? yes
Mar  7 02:43:11 myhost kernel: lowmem_reserve[]: 0 972 972 972
Mar  7 02:43:11 myhost kernel: Node 0 DMA32 free:3948kB min:3956kB low:4944kB high:5932kB active_anon:60kB inactive_anon:72kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:1032064kB manag
ed:999552kB mlocked:0kB dirty:12kB writeback:104kB mapped:32kB shmem:4kB slab_reclaimable:7120kB slab_unreclaimable:14460kB kernel_stack:2112kB pagetables:2948kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_t
mp:0kB pages_scanned:792 all_unreclaimable? yes
Mar  7 02:43:11 myhost kernel: lowmem_reserve[]: 0 0 0 0
Mar  7 02:43:11 myhost kernel: Node 0 DMA: 20*4kB (UM) 17*8kB (UM) 13*16kB (M) 14*32kB (UM) 8*64kB (UM) 4*128kB (M) 4*256kB (M) 0*512kB 1*1024kB (M) 0*2048kB 0*4096kB = 3944kB
Mar  7 02:43:11 myhost kernel: Node 0 DMA32: 934*4kB (UM) 28*8kB (UM) 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 3960kB
Mar  7 02:43:11 myhost kernel: 71 total pagecache pages
Mar  7 02:43:11 myhost kernel: 42 pages in swap cache
Mar  7 02:43:11 myhost kernel: Swap cache stats: add 245190, delete 245148, find 77026/136093
Mar  7 02:43:11 myhost kernel: Free swap  = 3118172kB
Mar  7 02:43:11 myhost kernel: Total swap = 3334140kB
Mar  7 02:43:11 myhost kernel: 262014 pages RAM
Mar  7 02:43:11 myhost kernel: 0 pages HighMem/MovableOnly
Mar  7 02:43:11 myhost kernel: 8149 pages reserved
Mar  7 02:43:11 myhost kernel: [ pid ]   uid  tgid total_vm      rss nr_ptes nr_pmds swapents oom_score_adj name
Mar  7 02:43:11 myhost kernel: [ 2054]     0  2054     5101        1      15       4      283             0 upstart-udev-br
Mar  7 02:43:11 myhost kernel: [ 2063]     0  2063    12362        1      28       4      184         -1000 systemd-udevd
Mar  7 02:43:11 myhost kernel: [ 3342]   102  3342     9780        1      23       3       89             0 dbus-daemon
Mar  7 02:43:11 myhost kernel: [ 3423]     0  3423    10864        1      26       3       85             0 systemd-logind
Mar  7 02:43:11 myhost kernel: [ 3441]     0  3441    15344        0      34       3      184         -1000 sshd
Mar  7 02:43:11 myhost kernel: [ 3450]     0  3450     4786        0      14       3       43             0 atd
Mar  7 02:43:11 myhost kernel: [ 3451]     0  3451     5915        0      17       4       65             0 cron
Mar  7 02:43:11 myhost kernel: [ 3457]   101  3457    63962        0      28       3      202             0 rsyslogd
Mar  7 02:43:11 myhost kernel: [ 3516]     0  3516     3919        1      13       3      156             0 upstart-file-br
Mar  7 02:43:11 myhost kernel: [ 3518]     0  3518     4014        0      13       3      265             0 upstart-socket-
Mar  7 02:43:11 myhost kernel: [ 3557]     0  3557    66396        0      32       3     1802             0 fail2ban-server
Mar  7 02:43:11 myhost kernel: [ 3600]     0  3600     3956        1      13       3       39             0 getty
Mar  7 02:43:11 myhost kernel: [ 3601]     0  3601     3198        1      12       3       37             0 getty
Mar  7 02:43:11 myhost kernel: [ 3673]     0  3673    26411        1      55       3      252             0 sshd
Mar  7 02:43:11 myhost kernel: [ 3740]  1000  3740    26411        1      52       3      253             0 sshd
Mar  7 02:43:11 myhost kernel: [ 3741]  1000  3741     5561        0      16       3      431             0 bash
Mar  7 02:43:11 myhost kernel: [ 3820]   103  3820     7863        1      21       3      152             0 ntpd
Mar  7 02:43:11 myhost kernel: [ 3837]  1000  3837    31990        0      58       4    12664             0 memcheck-amd64-
Mar  7 02:43:11 myhost kernel: [ 3841]  1000  3841    32006        0      59       4    12812             0 memcheck-amd64-
Mar  7 02:43:11 myhost kernel: [ 3844]  1000  3844    31950        0      57       4    12035             0 memcheck-amd64-
Mar  7 02:43:11 myhost kernel: [ 3849]  1000  3849    31902        0      56       4    11482             0 memcheck-amd64-
Mar  7 02:43:11 myhost kernel: [ 3853]  1000  3853     1087        0       7       3       27             0 lsof
Mar  7 02:43:11 myhost kernel: [ 3854]     0  3854    26140        5      55       3      230             0 sshd
Mar  7 02:43:11 myhost kernel: [ 3855]   104  3855    15699        0      33       3      202             0 sshd
Mar  7 02:43:11 myhost kernel: Out of memory: Kill process 3841 (memcheck-amd64-) score 11 or sacrifice child
Mar  7 02:43:11 myhost kernel: Killed process 3841 (memcheck-amd64-) total-vm:128024kB, anon-rss:0kB, file-rss:0kB

这是 /proc/meminfo

MemTotal:        1015460 kB
MemFree:          277508 kB
MemAvailable:     322032 kB
Buffers:            8336 kB
Cached:            42208 kB
SwapCached:        46088 kB
Active:            58844 kB
Inactive:         116100 kB
Active(anon):      34784 kB
Inactive(anon):    89620 kB
Active(file):      24060 kB
Inactive(file):    26480 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       3334140 kB
SwapFree:        3215756 kB
Dirty:                16 kB
Writeback:             0 kB
AnonPages:        121128 kB
Mapped:            15072 kB
Shmem:                 4 kB
Slab:              22668 kB
SReclaimable:       8028 kB
SUnreclaim:        14640 kB
KernelStack:        2016 kB
PageTables:         2532 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     3841868 kB
Committed_AS:     380460 kB
VmallocTotal:   34359738367 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
DirectMap4k:       14208 kB
DirectMap2M:     1034240 kB
DirectMap1G:           0 kB

答案1

这似乎是两个因素共同造成的问题:

  • 使用虚拟机。
  • 可能存在内核错误。

以下其中一行部分描述了为什么会发生这种情况:

3 月 7 日 02:43:11 myhost 内核:memcheck-amd64- 调用 oom-killer:gfp_mask=0x24002c2、order=0、oom_score_adj=0

另一行是这样的:

Mar  7 02:43:11 myhost kernel: 0 pages HighMem/MovableOnly

|第一行是分配给分配的 GFP 掩码。它基本上描述了内核允许/不允许做什么来满足此请求。掩码表示一组标准标志。然而,最后一位“2”表示内存分配应该来自区域HighMem

如果仔细观察 OOM 输出,您会发现HighMem/Normal区域实际上并不存在。

Mar  7 02:43:11 myhost kernel: Node 0 DMA: 20*4kB (UM) 17*8kB (UM) 13*16kB (M) 14*32kB (UM) 8*64kB (UM) 4*128kB (M) 4*256kB (M) 0*512kB 1*1024kB (M) 0*2048kB 0*4096kB = 3944kB
Mar  7 02:43:11 myhost kernel: Node 0 DMA32: 934*4kB (UM) 28*8kB (UM) 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 3960kB

HighMemNormal在 x86_64 上通常也这样称呼)倾向于将内存映射到 32 位系统上内核可直接访问的标准 896MiB 范围之外的区域。在 x86_64 上HighMem/Normal似乎涵盖了大小超过 3GiB 的所有页面。

DMA32包含一个用于内存的区域,该区域可在 32 位 DMA 设备上访问,也就是说,您可以使用 4 字节指针对其进行寻址。我相信DMA是针对 16 位 DMA 设备的。

一般来说,在低内存系统上Normal不会存在,因为它DMA32已经覆盖了所有可用的虚拟地址。

您之所以会 OOM kill 是因为某个HighMem区域的内存分配中没有可用页面。由于内存不足处理程序根本无法通过交换、终止其他进程或任何其他技巧来让该区域有页面可用,因此 OOM-killer 会直接将其终止。

我认为这是由于主机 VM 在启动时膨胀造成的。在 KVM 系统上,您可以设置两个值。

  • 當前的記憶。
  • 可用内存。

其工作方式是,您可以热添加内存到您的服务器,直到达到可用内存为止。但您的系统实际上获得的是当前内存。

当 KVM VM 启动时,它会以可能分配的最大内存(可用内存)开始。在系统启动阶段,KVM 会通过膨胀逐渐收回这部分内存,让您保留当前的内存设置。

我相信这就是这里发生的事情。Linode 允许您扩展内存,在系统启动时为您提供更多内存。

Normal/HighMem这意味着在系统生命周期开始时有一个区域。当虚拟机管理程序将其膨胀时,正常区域会从内存管理器中消失。但是,我怀疑设置所述区域是否可从中分配的标志是不是应该清除时却被清除。这导致内核尝试从不存在的区域进行分配。

为了解决这个问题,您有两个选择。

  1. 在内核邮件列表中提出这个问题,看看这是否真的是一个错误,预期的行为,或者与我所说的完全无关。

  2. 请求 linode 将系统上的“可用内存”设置为与“当前内存”相同的 1GiB 分配。这样系统就不会膨胀,也不会在启动时进入正常区域,从而保持标志清晰。祝你好运让他们做到这一点!

您应该能够通过在 KVM 设置中设置您自己的虚拟机来测试这种情况,可用设置为 6GiB,当前设置为 1GiB,并使用相同的内核运行测试,以查看是否发生上述行为。如果发生,请将“可用”设置更改为等于当前 1GiB,然后重复测试。

我在这里做了一些有根据的猜测,并阅读了一些字里行间的内容以得出这个答案,但我所说的似乎符合已经概述的事实。

我建议测试我的假设并让我们都知道结果。

答案2

要回答您的标题问题,请使用oom_score_adj(内核> = 2.6.36)或更早的内核(> = 2.6.11)oom_adj,请参阅 man进程

/proc/[pid]/oom_score_adj(自 Linux 2.6.36 起)此文件可用于调整用于选择在内存不足的情况下终止哪个进程的不良启发式方法……

/proc/[pid]/oom_adj(自 Linux 2.6.11 起)此文件可用于调整在内存不足(OOM)情况下选择应终止哪个进程的分数……

还有很多内容需要阅读,但将 oom_score_adj 设置为 -1000 或将 oom_adj 设置为 -17 将实现您想要的效果。

问题是其他东西会被杀死。也许最好确定调用 OOM 的原因并处理它。

答案3

一些想法(来自我上面的评论)以及有关您的情况的有趣读物的链接:

答案4

我会尝试启用过度使用,看看是否有帮助。您的进程似乎在调用中失败fork,该调用需要与初始进程一样多的虚拟内存。overcommit_memory=2这不会让您的进程免受 OOM 杀手的侵害,它只是防止您的进程通过分配过多而触发它。其他进程可能会产生不相关的分配错误(例如获取连续的内存块),这仍然会触发 OOM 杀手并处置您的进程。

或者(更重要的是),正如一些评论所建议的那样,购买更多的 RAM。

相关内容