ArmV8嵌入式系统memtester大内存mlock首次失败原因及解决办法
问题描述
我在无交换内存的ArmV8嵌入式系统上运行BusyBox,系统启动后执行free命令,输出如下:
/ # free total used free shared buff/cache available Mem: 1009476 18396 989128 0 1952 957260
随后运行申请690M内存的memtester(实际调用mlock),触发OOM-killer失败,日志如下:
pagesize is 4096 pagesizemask is 0xfffffffffffff000 want 690MB (723517440 bytes) got 690MB (723517440 bytes), trying mlock ...[ 106.591843] memtester invoked oom-killer: gfp_mask=0x14040c0(GFP_KERNEL|__GFP_COMP), nodemask=(null), order=0, oom_score_adj=0 [ 106.603174] memtester cpuset=/ mems_allowed=0 [ 106.607474] CPU: 1 PID: 1392 Comm: memtester Tainted: G O 4.14.76-19.0.0 #1 [ 106.620744] Call trace: [ 106.623161] [<ffff0000080892a8>] dump_backtrace+0x0/0x358 [ 106.628475] [<ffff000008089614>] show_stack+0x14/0x20 [ 106.633448] [<ffff000008b35a10>] dump_stack+0x90/0xb0 [ 106.638421] [<ffff000008192e14>] dump_header+0x90/0x1e8 [ 106.643562] [<ffff000008191f90>] oom_kill_process+0xd0/0x518 [ 106.649130] [<ffff000008192a00>] out_of_memory+0x180/0x490 [ 106.654529] [<ffff000008197ff4>] __alloc_pages_nodemask+0xadc/0xb60 [ 106.660700] [<ffff0000081e6fd8>] alloc_pages_current+0x80/0xf0 [ 106.666440] [<ffff0000081efb0c>] new_slab+0x40c/0x4e8 [ 106.671410] [<ffff0000081f1a9c>] ___slab_alloc+0x474/0x548 [ 106.676809] [<ffff0000081f1b94>] __slab_alloc.isra.22+0x24/0x38 [ 106.682634] [<ffff0000081f2318>] kmem_cache_alloc+0x188/0x1c0 [ 106.688291] [<ffff000008305614>] nfs_readhdr_alloc+0x1c/0x30 [ 106.693861] [<ffff000008304400>] nfs_generic_pg_pgios+0x20/0xc0 [ 106.699685] [<ffff000008303db4>] nfs_pageio_doio+0x34/0x80 [ 106.705083] [<ffff000008304770>] __nfs_pageio_add_request+0xb0/0x370 [ 106.711335] [<ffff0000083050c4>] nfs_pageio_add_request+0x14c/0x330 [ 106.717502] [<ffff00000830595c>] readpage_async_filler+0x1c4/0x210 [ 106.723585] [<ffff00000819d5c4>] read_cache_pages+0xb4/0x1a0 [ 106.729153] [<ffff000008306394>] nfs_readpages+0xcc/0x1c0 [ 106.734466] [<ffff00000819d80c>] __do_page_cache_readahead+0x15c/0x230 [ 106.740892] [<ffff00000818fd58>] filemap_fault+0x308/0x5a0 [ 106.746292] [<ffff0000081bf2f0>] __do_fault+0x20/0x70 [ 106.751263] [<ffff0000081c4970>] __handle_mm_fault+0xa78/0x1010 [ 106.757089] [<ffff0000081c5038>] handle_mm_fault+0x130/0x1d0 [ 106.762660] [<ffff0000080a0c6c>] do_page_fault+0x134/0x3e8 [ 106.768058] [<ffff0000080a0f68>] do_translation_fault+0x48/0x50 [ 106.773883] [<ffff000008080ae4>] do_mem_abort+0x3c/0x98 [ 106.779024] [<ffff000008080bd4>] do_el0_ia_bp_hardening+0x44/0xa0
之后我运行某应用并将其杀死,再次执行free命令结果与之前一致,但此时运行申请1G内存的memtester成功锁定了934MB:
/ # memtester 1G 1 memtester version 4.3.0 (64-bit) Copyright (C) 2001-2012 Charles Cazabon. Licensed under the GNU General Public License version 2 (only). pagesize is 4096 pagesizemask is 0xfffffffffffff000 want 1024MB (1073741824 bytes) got 934MB (979906560 bytes), trying mlock ...locked.
请问为何首次运行690MB的memtester会失败?如何无需运行应用就能让其成功?
问题分析与解决
首次运行失败的原因
从OOM日志的调用栈能看出,触发OOM的是NFS相关的内核内存分配请求,而非memtester的mlock直接导致:
- 系统刚启动时,内核slab分配器(管理内核对象内存)处于初始状态,可用的slab缓存不足。当memtester申请内存并执行
mlock时,内核需要分配页表、slab对象等内核态内存,此时NFS模块刚好也在尝试分配内存(从nfs_readhdr_alloc等调用可验证),两者竞争内存资源,触发了OOM-killer。 - 首次运行时内存碎片化更严重,内核无法凑出连续内存块满足内核态内存需求;而运行并杀死应用后,内存被重新整理,碎片化程度降低,同时slab缓存被预热,有了足够可用的内核内存,因此memtester能成功锁定更多内存。
另外注意:free命令的available是用户态可用内存的估算值,不包含内核预留内存,所以即使显示有957MB可用,内核态内存不足时依然会触发OOM。
无需运行应用的解决方法
- 预热内核slab缓存:手动触发内核内存分配操作,比如执行
find / -type f | head -1000(遍历大量文件,让文件系统模块分配slab对象),或者dd if=/dev/zero of=/tmp/test bs=1M count=100 && rm /tmp/test,通过读写操作让内核提前分配好所需的slab缓存。 - 调整内核内存预留参数:如果允许修改内核参数,可适当降低
vm.min_free_kbytes(内核预留的最小空闲内存),命令为echo 4096 > /proc/sys/vm/min_free_kbytes(数值需根据实际情况调整,注意此操作可能影响系统稳定性)。 - 禁用NFS相关模块:如果系统不需要NFS,可在启动时禁用NFS客户端/服务端模块,避免NFS后台触发内存分配请求,减少竞争。
- 整理内存碎片:执行
echo 3 > /proc/sys/vm/drop_caches清理缓存,若内核支持,再执行echo 1 > /proc/sys/vm/compact_memory主动压缩内存,降低碎片化程度。
内容的提问来源于stack exchange,提问作者Johnnie Walker
相关产品推荐
相关产品推荐

