这个问题相当长,所以我会在顶部提出问题,然后通过我的解决问题的方法:
- (基于 Busybox 的) rm 是否因为没有足够的连续 RAM 而未执行?
- 如果是这样,是否有一种轻量级方法对 DMA 进行碎片整理 - 无需重新启动系统?
- 如果不是,是什么原因造成的?我怎样才能防止将来再次发生这种情况?
在我们的测试系统在过去几天中相当密集地运行之后,我通过远程登录进入系统并检查了测试结果。当我要删除一些数据时,系统返回了命令行(就好像命令已正确执行一样)。当我检查目录中的另一组结果时,我看到该文件仍然存在(使用 ls)。
此后,我注意到越来越多的 shell 命令没有按预期执行。
我将从输出开始消息rm 未能正确执行后:
从进程 6821 (rm) 分配长度 61440 失败
每个 CPU 的 DMA:
CPU 0:嗨:0,btch:1 美元:0
Active_anon:0 active_file:1 inactive_anon:0 inactive_file:0 不可删除:6 脏:0 写回:0 不稳定:0 空闲:821 平板:353 映射:0 页表:0 反弹:0
DMA 空闲:3284kB 最小值:360kB 低:448kB 高:540kB active_anon:0kB inactive_anon:0kB active_file:4kB inactive_file:0kB 不可删除:24kB 存在:8128kB Pages_scanned:0 all_unreclaimable?不
lowmem_reserve[]: 0 0 0
DMA:31*4kB 47*8kB 42*16kB 64*32kB 1*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 3284kB
总共 14 个页面缓存页面
无法为过程数据分配 RAM,错误号 12
最初,我认为我无法在最大部分的连续内存中运行该程序。这意味着 DMA 碎片太多,我必须找到一种方法让系统对内存进行碎片整理。
然后我做了一个快速的数学/健全性检查,并意识到该程序应该能够在唯一的 64kB 连续内存插槽中运行。Rm 请求 61440 字节(60kB)。
我做了一个很好的旧“手动碎片整理”并重新启动了系统。当我重新启动系统时,我输出 /proc/buddyinfo:
Node 0, zone DMA 2 8 3 12 0 1 0 1 0 1 0
我怀疑映射到:
- 2×4kB
- 8 x 8 KB
- 3 x 16 KB
- 12 x 32 KB
- 1×128kB
- 1 x 512 KB
但是,如果对上面的值列表进行求和,则它与以下的输出不匹配/proc/内存信息:
MemTotal: 6580 kB
MemFree: 3164 kB
Buffers: 0 kB
Cached: 728 kB
SwapCached: 0 kB
Active: 176 kB
Inactive: 524 kB
Active(anon): 0 kB
Inactive(anon): 0 kB
Active(file): 176 kB
Inactive(file): 524 kB`
Unevictable: 0 kB
Mlocked: 0 kB
MmapCopy: 844 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 0 kB
Mapped: 0 kB
Slab: 1268 kB
SReclaimable: 196 kB
SUnreclaim: 1072 kB
PageTables: 0 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 3288 kB
Committed_AS: 0 kB
VmallocTotal: 0 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
回顾一下,我的问题是:
- rm 没有执行是因为没有足够的连续 RAM 吗?
- 如果是这样,是否有一种轻量级方法对 DMA 进行碎片整理 - 无需重新启动系统?
- 如果不是,是什么原因造成的?我怎样才能防止将来再次发生这种情况?
我正在使用 Lantronix 的 XPort Pro(8MB,Linux 操作系统),运行 uClinux 版本 2.6.30。使用的外壳是安静的。
答案1
关于内存碎片整理,引用内核文档:
目前,这些文件位于
/proc/sys/vm
:[...]
compact_memory
仅在以下情况下可用配置_压缩已设置。当
1
写入文件时,所有区域都会被压缩,以便在可能的情况下在连续块中提供可用内存。这在分配大页面时可能很重要,尽管进程也会根据需要直接压缩内存。
这意味着以下命令(使用 root 权限执行,并且如果启用了上述内核选项)
echo 1 > /proc/sys/vm/compact_memory
应该告诉内核尝试尽可能多地对内存进行碎片整理。请注意,例如在某些 RHEL6 版本上,这可能会使内核崩溃......
答案2
这花了一些时间,但我想我应该推迟回答,直到我得到所有 3 个子问题的答案。
在开始之前,我要提一下,当谈到“整理”工作记忆时,正确的术语是“压缩”工作记忆。
1. rm没有执行是因为没有足够的连续RAM吗?
我的结论是正确的 - rm 没有执行,因为没有足够的连续 RAM。系统一直在获取 RAM 并将其碎片化,从而使其无法回收。
2. 如果是,是否有一种轻量级方法对 DMA 进行碎片整理 - 无需重新启动系统?
事实证明,除了重新启动嵌入式系统外,没有其他方法可以压缩内存。对于没有 MMU 的系统,预防才是王道。
我的一部分思考是否有可能破解 Linux 内核以在软件中模拟 MMU。我想如果可能的话,早就有人这么做了。我无法想象这是一个全新的概念;)
3. 我怎样才能防止以后再发生这种情况?
对于这个项目,我使用 cron 在每次需要时手动启动程序。更好的方法是在启动时调用程序,然后强制程序休眠直到需要为止。这样,就不需要在每次使用时分配内存。从而减少碎片。
在项目的第一次迭代中,我们依靠 shell 脚本调用来执行关键功能(例如 rm)。如果不需要的话,我们认为没有必要重新发明轮子。
但是,我建议在无 MMU 的系统中尽可能避免使用 shell -
(问题,如果执行会发生什么ls -la /path/to/directory/ | grep file-i-seek
?)
(回答:它启动一个新的子进程)
如果您需要在 C 程序中实现一些核心 shell 脚本功能,我建议您查看中使用的源代码忙碌盒。您很可能会在嵌入式系统中使用 C 语言。