RAM 碎片整理 / OOM 失败

RAM 碎片整理 / OOM 失败

这个问题相当长,所以我会在顶部提出问题,然后通过我的解决问题的方法:

  1. (基于 Busybox 的) rm 是否因为没有足够的连续 RAM 而未执行?
  2. 如果是这样,是否有一种轻量级方法对 DMA 进行碎片整理 - 无需重新启动系统?
  3. 如果不是,是什么原因造成的?我怎样才能防止将来再次发生这种情况?

在我们的测试系统在过去几天中相当密集地运行之后,我通过远程登录进入系统并检查了测试结果。当我要删除一些数据时,系统返回了命令行(就好像命令已正确执行一样)。当我检查目录中的另一组结果时,我看到该文件仍然存在(使用 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

回顾一下,我的问题是:

  1. rm 没有执行是因为没有足够的连续 RAM 吗?
  2. 如果是这样,是否有一种轻量级方法对 DMA 进行碎片整理 - 无需重新启动系统?
  3. 如果不是,是什么原因造成的?我怎样才能防止将来再次发生这种情况?

我正在使用 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 语言。

相关内容