一个让我困惑的 oom 杀手

一个让我困惑的 oom 杀手

当我看到有足够的内存可用时,我无法理解为什么内核会发出这个 oom Killer:

另外为什么分配了这么多内核缓存页面?看了之后说内存够用

普通的

DMA

正常空闲线路

这是一个基于嵌入式 nand 闪存的设备,具有 256 MB RAM

内核:2.6.31

 myshellscript invoked oom-killer: gfp_mask=0xd0, order=2, oomkilladj=0 
 Backtrace: 
 [<c0106494>] (dump_backtrace+0x0/0x110) from [<c03641a0>] (dump_stack+0x18/0x1c) 
 r6:000000d0 r5:c9040c60 r4:00000002 r3:c0448690 
 [<c0364188>] (dump_stack+0x0/0x1c) from [<c015a314>] (oom_kill_process.clone.11+0x60/0x1b4) 
 [<c015a2b4>] (oom_kill_process.clone.11+0x0/0x1b4) from [<c015a738>] (__out_of_memory+0x154/0x178) 
 r8:c21e86e0 r7:001fb000 r6:00000002 r5:000000d0 r4:c9b6e000 
 [<c015a5e4>] (__out_of_memory+0x0/0x178) from [<c015a980>] (out_of_memory+0x68/0xa0) 
 [<c015a918>] (out_of_memory+0x0/0xa0) from [<c015d230>] (__alloc_pages_nodemask+0x42c/0x520) 
 r5:00000002 r4:000000d0 
 [<c015ce04>] (__alloc_pages_nodemask+0x0/0x520) from [<c015d388>] (__get_free_pages+0x18/0x44) 
 [<c015d370>] (__get_free_pages+0x0/0x44) from [<c0109418>] (get_pgd_slow+0x1c/0xe0) 
 [<c01093fc>] (get_pgd_slow+0x0/0xe0) from [<c0129ab0>] (mm_init.clone.43+0xb0/0xf0) 
 r7:c90858c0 r6:00000000 r5:c90858c0 r4:ce1a6680 
 [<c0129a00>] (mm_init.clone.43+0x0/0xf0) from [<c0129c40>] (mm_alloc+0x34/0x44) 
 r6:0009230c r5:c90858c0 r4:ce1a6680 r3:00000000 
 [<c0129c0c>] (mm_alloc+0x0/0x44) from [<c0180f70>] (bprm_mm_init+0x14/0x148) 
 r4:c5154000 r3:cd472564 
 [<c0180f5c>] (bprm_mm_init+0x0/0x148) from [<c01812d0>] (do_execve+0xa8/0x254) 
 [<c0181228>] (do_execve+0x0/0x254) from [<c0106000>] (sys_execve+0x3c/0x5c) 
 [<c0105fc4>] (sys_execve+0x0/0x5c) from [<c0102e80>] (ret_fast_syscall+0x0/0x2c) 
 r7:0000000b r6:0009230c r5:0009237c r4:000922fc 
 Mem-info: 
 DMA per-cpu: 
 CPU 0: hi: 18, btch: 3 usd: 0 
 Normal per-cpu: 
 CPU 0: hi: 42, btch: 7 usd: 0 
 Active_anon:28162 active_file:16 inactive_anon:18037 
 inactive_file:13 unevictable:0 dirty:0 writeback:0 unstable:0 
 free:9998 slab:2447 mapped:164 pagetables:701 bounce:0 
 DMA free:17128kB min:1560kB low:1948kB high:2340kB active_anon:51068kB inactive_anon:10320kB active_file:24kB inactive_file:0kB unevictable:0kB present:97536kB pages_scanned:0 all_unreclaimable? no 
 lowmem_reserve[]: 0 158 158 
 Normal free:22864kB min:2600kB low:3248kB high:3900kB active_anon:61580kB inactive_anon:61828kB active_file:40kB inactive_file:52kB unevictable:0kB present:162560kB pages_scanned:0 all_unreclaimable? no 
 lowmem_reserve[]: 0 0 0 
 DMA: 2358*4kB 912*8kB 25*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB 0*8192kB 0*16384kB = 17128kB 
 Normal: 4266*4kB 657*8kB 32*16kB 1*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB 0*8192kB 0*16384kB = 22864kB 
 26591 total pagecache pages 
 0 pages in swap cache 
 Swap cache stats: add 0, delete 0, find 0/0 
 Free swap = 0kB 
 Total swap = 0kB 
 65536 pages of RAM 
 10471 free pages 
 3967 reserved pages 
 2447 slab pages 
 892 shared page count 
 389 shared pages
 620 mapped shared page count
 177 mapped shared pages
 0 pages swap cached
 2481 dma reserved pages
 19892 total user pages
 20512 RSS sum by tasks
 20512 RSS sum by page stats
 164 user cache pages
 26427 kernel cache pages

答案1

编辑:这个答案是不正确的。虽然仍然是调用 oom-killer 的可能原因,但它不是本例中的原因。


看起来这是由于内存碎片造成的。

根据您提供的输出,您拥有的最高阶连续内存块是normal区域中的 32kb 块。这意味着如果任何尝试分配大于 32kb 的内存块,它将失败。
通常这并不一定意味着 oom-killer 将被调用(否则应用程序可能会请求大量内存并从而触发 OOM),但是这是正在尝试分配内存的内核,因此它有点多严肃的。在这种情况下,看起来分配是通过启动一个新进程触发的,并且内核正在尝试为该进程分配内存。

内核会自动尝试压缩(碎片整理)内存并获取更大的可用连续内存块,但某些页面无法移动。而且系统运行的时间越长,这些“不可移动”的页面就越分散。

所以基本上,你无能为力。实际上,唯一的选择是终止进程,以便释放那些不可移动的页面。


至于上面的输出中表示内存碎片的内容,是以下几行

 DMA: 2358*4kB 912*8kB 25*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB 0*8192kB 0*16384kB = 17128kB 
 Normal: 4266*4kB 657*8kB 32*16kB 1*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB 0*8192kB 0*16384kB = 22864kB

像这样的条目32*16kb意味着有 32 个 16kb 连续的空闲内存块。

答案2

我们正在处理未知嵌入式平台上的未知应用程序。显然,如果我们对这两点有更多的信息,我们可能有更好的机会回答 abc 的问题。确切地知道脚本试图获取多少内存也很有用。


我认为 Patrick 是正确的 - 没有足够的连续 DMA 来允许进程运行。这可能是由于以下原因:

  1. 嵌入式系统可能具有分页的自定义实现
  2. 嵌入式系统可能没有 MMU
  3. 该脚本可以调用精确访问 DMA 的 IO 驱动程序
  4. 该脚本可能包含需要连续内存的第三方程序

ETC...

我相信,如果减少 DMA 内存碎片,OOM 杀手就不会跳转。快速测试的最简单方法是重新启动嵌入式设备并查看 OOM-killer 是否仍在被调用。

现在,我将继续在互联网上寻找一种轻量级、嵌入式友好的方式来整理内存碎片,而无需重置设备。

您可能会对这个链接感兴趣: http://bl0rg.krunch.be/oom-frag.html

相关内容