当物理内存不足但交换空间充足时,如何让 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
HighMem
(Normal
在 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
这意味着在系统生命周期开始时有一个区域。当虚拟机管理程序将其膨胀时,正常区域会从内存管理器中消失。但是,我怀疑设置所述区域是否可从中分配的标志是不是应该清除时却被清除。这导致内核尝试从不存在的区域进行分配。
为了解决这个问题,您有两个选择。
在内核邮件列表中提出这个问题,看看这是否真的是一个错误,预期的行为,或者与我所说的完全无关。
请求 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
一些想法(来自我上面的评论)以及有关您的情况的有趣读物的链接:
我建议您检查 1) 您是否可以使用当前内核和配置(和 CPU)处理超过 3Gb 的地址 [因为如果 3Gb 是您的系统和操作系统的限制,那么您就超出了它]。2) 您是否允许交换,并且交换子系统已安装并正常工作。祝您好运(我不会解释如何操作,因为这取决于您的设置和具体情况。搜索引擎会有所帮助)。并且您没有溢出内核表(nb of pids?或其他任何东西(有些可能可以在内核编译时设置)。
检查整个事物(硬件或虚拟机的模拟硬件等)是否为 64 位。(例如:https://askubuntu.com/questions/313379/i-installed-a-64-bit-os-in-a-32-bit-processor/313381)。CPU、主机操作系统、虚拟机子系统和虚拟机操作系统都应该启用 64 位,否则您将无法拥有真正的 64 位虚拟机
一些好书:
- 如何诊断 oom-killer 杀死进程的原因:就在这个网站上。提供了一个很好的链接,http://linux-mm.org/OOM_Killer另一位用户介绍了 atop 工具,它可以帮助诊断发生了什么
- https://www.kernel.org/doc/gorman/html/understand/understand016.html:3.12 显示了 OOM 的决策树(旧版本,因此 ymmv。阅读源代码 ^^)
- https://lwn.net/Articles/317814/:“驯服 OOM 杀手”展示了如何创建一个“不可战胜”的组并将你的进程放入其中
- http://eloquence.marxmeier.com/sdb/html/linux_limits.html:显示一些常见的内核限制
- http://win.tue.nl/~aeb/linux/lk/lk-9.html:虽然它确实过时了(因此只涉及 32 位架构...),但仍然值得一读(某些分配方法浪费了空间等)。
- http://bl0rg.krunch.be/oom-frag.html显示了为什么“即使还有大量可用内存,也可能调用 OOM killer”的一些原因
- https://stackoverflow.com/questions/17935873/malloc-fails-when-there-is-still-plenty-of-swap-left:提供一种方法来检查你的系统如何分配内存
- https://serverfault.com/a/724518/146493:非常好的答案,提供了详细的方式来了解真正发生了什么(但是......针对的是 32 位问题,所以 ymmv。不过,仍然是一个令人难以置信的阅读和答案)。
最后:http://www.oracle.com/technetwork/articles/servers-storage-dev/oom-killer-1911807.html展示了一种防止您的进程成为 oom killer 目标的方法!(
echo -17 > /proc/PROCESSPID/oom_adj
)。可能容易发生变化,也可能是一件坏事(导致其他类型的故障,因为系统现在不能简单地杀死主要罪犯……)请谨慎使用。@iain 注意,“oom_adj”适用于较旧的内核,在较新的内核中应该用“oom_score_adj”替换。谢谢,Iain)
答案4
我会尝试启用过度使用,看看是否有帮助。您的进程似乎在调用中失败fork
,该调用需要与初始进程一样多的虚拟内存。overcommit_memory=2
这不会让您的进程免受 OOM 杀手的侵害,它只是防止您的进程通过分配过多而触发它。其他进程可能会产生不相关的分配错误(例如获取连续的内存块),这仍然会触发 OOM 杀手并处置您的进程。
或者(更重要的是),正如一些评论所建议的那样,购买更多的 RAM。