为什么还有足够的内存(即“58*4096kB (C)”)可以使用时却出现“页面分配失败”?

为什么还有足够的内存(即“58*4096kB (C)”)可以使用时却出现“页面分配失败”?

为什么还有“58*4096kB (C)”可用却出现“页面分配失败”?

你看,内核在分配 order:10 大小的内存时会抱怨(即页面分配失败:order:10)。但确实有空闲块(即“58*4096kB (C)”)。所以我认为它不应该抱怨,因为确实有足够的可用内存。

这是相关日志:

[ 2161.623563] xxxx: page allocation failure: order:10, mode:0x2084020(GFP_ATOMIC|__GFP_COMP)
[ 2161.632085] CPU: 0 PID: 179 Comm: AiApp Not tainted 4.9.56 #53
[ 2161.637947] 
Call Trace:
[<802f63f2>] dump_stack+0x1e/0x3c
[<800f6cf4>] warn_alloc+0x100/0x148
[<800f709c>] __alloc_pages_nodemask+0x2bc/0xb5c
[<801120fe>] kmalloc_order+0x26/0x48
[<80112158>] kmalloc_order_trace+0x38/0x98
[<8012c5d8>] __kmalloc+0xf4/0x12c
[<8048ac78>] alloc_ep_req+0x5c/0x98
[<8048f232>] source_sink_recv+0x2a/0xe0
[<8048f35e>] usb_sourcesink_bulk_read+0x76/0x1c8
[<8048f770>] usb_sourcesink_read+0xfc/0x2c8
[<80134d58>] __vfs_read+0x30/0x108
[<80135c14>] vfs_read+0x94/0x128
[<80136d12>] SyS_read+0x52/0xd4
[<8004a246>] csky_systemcall+0x96/0xe0
[ 2161.689204] Mem-Info:
[ 2161.691518] active_anon:3268 inactive_anon:2 isolated_anon:0
[ 2161.691518]  active_file:1271 inactive_file:89286 isolated_file:0
[ 2161.691518]  unevictable:0 dirty:343 writeback:0 unstable:0
[ 2161.691518]  slab_reclaimable:2019 slab_unreclaimable:644
[ 2161.691518]  mapped:4282 shmem:4 pagetables:59 bounce:0
[ 2161.691518]  free:62086 free_pcp:199 free_cma:60234

[ 2161.724334] Node 0 active_anon:13072kB inactive_anon:8kB active_file:5084kB inactive_file:357144kB unevictable:0kB isolated(anon):0kB isolated(file):0kB mapped:17128kB dirty:1372kB writeback:0kB shmem:16kB writeback_tmp:0kB unstable:0kB pages_scanned:0 all_unreclaimable? no

[ 2161.748626] Normal free:248344kB min:2444kB low:3052kB high:3660kB active_anon:13072kB inactive_anon:8kB active_file:5084kB inactive_file:357144kB unevictable:0kB writepending:1372kB present:1048572kB managed:734568kB mlocked:0kB slab_reclaimable:8076kB slab_unreclaimable:2576kB kernel_stack:608kB pagetables:236kB bounce:0kB free_pcp:796kB local_pcp:796kB free_cma:240936kB
[ 2161.781670] lowmem_reserve[]: 0 0 0

[ 2161.785225] Normal: 4*4kB (UEC) 3*8kB (EC) 3*16kB (UEC) 2*32kB (UE) 2*64kB (UE) 2*128kB (UE) 2*256kB (EC) 1*512kB (E) 3*1024kB (UEC) 3*2048kB (UEC) 58*4096kB (C) = 248344kB
90573 total pagecache pages

[ 2161.803526] 262143 pages RAM
[ 2161.806410] 0 pages HighMem/MovableOnly
[ 2161.810264] 78501 pages reserved
[ 2161.813509] 90112 pages cma reserved

答案1

您没有提供太多信息,例如发生这种情况的条件是什么,您运行的是哪个系统(Linux,Android,...)等等。

无论如何,你可以开始微调你的内核。您可以使用vm.min_free_kbytes,它告诉内核在所有情况下都保持此类内存空闲(单位为 KiB)。

kernel.org 文档(“/proc/sys/vm/* 的文档”)

最小可用千字节数:

这用于强制 Linux VM 保持最少的可用千字节。 VM 使用此数字来计算WMARK_MIN系统中每个 lowmem 区域的水印 [ ] 值。每个 lowmem 区域根据其大小按比例获得一定数量的保留空闲页面。

需要一些最小量的内存来满足PF_MEMALLOC 分配;如果您将其设置为低于 1024 KB **,您的系统将变得微妙地崩溃,并且在高负载下容易出现死锁。

设置得太高会立即导致机器 OOM。

要永久更改此设置,您可以执行以下操作(降低到 16 MiB):

echo "vm.min_free_kbytes=16384" >> /etc/sysctl.conf

要尝试并测试一切是否正常,您可以仅针对当前会话进行更改:

sysctl -w vm.min_free_kbytes=16384

该信息的来源是kernel.org 文档


您的问题是,为什么当您有可用内存时会出现页面错误 - 即使您有比上面指定的更多的可用内存?

如果您的可用内存超过 指定的限制vm.min_free_kbytes,那么答案很可能是内存碎片 (您可能还有其他的,例如有故障的内存模块)。

详细信息如下:

order:10 位间接告诉您请求了多少页。这样的顺序被认为是高阶的,因为它实际上请求 2 10 (2^10),即 1024 页或 4096 KiB 连续内存!

这些mode是传递给内核内存分配器的标志。你有一个mode:0x2084020 (GFP_ATOMIC|__GFP_COMP) - 内核模式分配器(标志)。对于这一点,您需要具备一些内核源代码知识。详细解释您的标志。

旗帜GFP_ATOMIC

GFP_ATOMIC标志指示内存分配器永远不会阻塞。在无法睡眠的情况下使用此标志(它必须保持原子性),例如中断处理程序、下半部分和持有锁的进程上下文代码。由于内核无法阻止分配并尝试释放足够的内存来满足请求,因此指定的分配GFP_ATOMIC成功的机会比未指定的分配要小。尽管如此,如果您当前的环境无法入睡,那么这是您唯一的选择。 ……

旗帜__GFP_COMP

复合页面元数据

来自 include/linux/gfp.h (参见来源1,来源2)。

该页框属于扩展页

这就回到了所需内存的大小。扩展页面允许您拥有 4 MiB 页面框架,而不仅仅是 4 KiB。推荐阅读: Linux内核书和优秀文章: Kernel Korner - 在内核中分配内存了解更多信息。

如您所见,您请求 4096 KiB 的非阻塞分配,分配必须保持原子性;您不能阻止分配并尝试释放内存(连续)。因此分配失败。

可以在以下位置找到标志include/linux/gfp.h (请参阅来源1,来源2)。

编辑 – 内核版本 4.9

这是内核版本 4.9 的重要信息。这个确切的内核版本 (4.9) 出现了回归,导致 SWAP 根本无法使用 –OOM 但未使用交换区 (kernel.org)

修复此问题的推荐方法是将内核升级到至少 4.10.8。此版本及以上版本应该已修复此错误 - 更多信息请参见OOM 但未使用交换区(红帽)

__________________
*   据推测,它们的意思是千字节。
**大概他们的意思是 KiB。

相关内容