打开“ OSERror: [ Errno 12] Can not distribution memory”

注意: 这个问题最初是问 给你,但赏金时间过期,即使没有找到一个可以接受的答案。我重新问这个问题,包括原问题中提供的所有细节。

Python 脚本使用 安排好了模块每60秒运行一组类函数:

# sc is a sched.scheduler instance
sc.enter(60, 1, self.doChecks, (sc, False))

该脚本使用代码 给你作为守护进程运行。

作为 doChecks 的一部分调用的许多类方法使用 子流程模块调用系统函数以获取系统统计信息:

ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE).communicate()[0]

在整个脚本崩溃并出现以下错误之前的一段时间内,这种方法运行良好:

File "/home/admin/sd-agent/checks.py", line 436, in getProcesses
File "/usr/lib/python2.4/subprocess.py", line 533, in __init__
File "/usr/lib/python2.4/subprocess.py", line 835, in _get_handles
OSError: [Errno 12] Cannot allocate memory

一旦脚本崩溃,服务器上 free-m 的输出如下:

$ free -m
total       used       free     shared     buffers    cached
Mem:                894        345        549          0          0          0
-/+ buffers/cache:  345        549
Swap:                 0          0          0

服务器正在运行 CentOS 5.3。我不能复制在我自己的 CentOS 框,也没有任何其他用户报告同样的问题。

正如最初的问题所建议的那样,我已经尝试了很多方法来调试这个问题:

  1. 在 Popen 调用之前和之后记录 free-m 的输出。内存使用没有明显的变化,也就是说,内存没有随着脚本的运行而逐渐耗尽。

  2. 我将 close _ fds = True 添加到 Popen 调用中,但是这没有什么区别——脚本仍然因为相同的错误而崩溃。建议的 给你给你

  3. 我检查了 RLIMIT _ DATA 和 RLIMIT _ AS 上显示(- 1,-1)的 RLIMIT,如建议的 给你所示。

  4. 一篇文章 提出没有交换空间可能是原因,但交换实际上是可用的(根据网络主机) ,这也被认为是一个假的原因 给你

  5. 进程被关闭,因为这是使用的行为。Communication ()作为 Python 源代码和注释 给你的备份。

完整的检查可以在 我是 GitHub上找到,其中 getProcess 函数是从第442行定义的。这由 doChecks ()从第520行开始调用。

该脚本在崩溃前使用 strace 运行,输出如下:

recv(4, "Total Accesses: 516662\nTotal kBy"..., 234, 0) = 234
gettimeofday({1250893252, 887805}, NULL) = 0
write(3, "2009-08-21 17:20:52,887 - checks"..., 91) = 91
gettimeofday({1250893252, 888362}, NULL) = 0
write(3, "2009-08-21 17:20:52,888 - checks"..., 74) = 74
gettimeofday({1250893252, 888897}, NULL) = 0
write(3, "2009-08-21 17:20:52,888 - checks"..., 67) = 67
gettimeofday({1250893252, 889184}, NULL) = 0
write(3, "2009-08-21 17:20:52,889 - checks"..., 81) = 81
close(4)                                = 0
gettimeofday({1250893252, 889591}, NULL) = 0
write(3, "2009-08-21 17:20:52,889 - checks"..., 63) = 63
pipe([4, 5])                            = 0
pipe([6, 7])                            = 0
fcntl64(7, F_GETFD)                     = 0
fcntl64(7, F_SETFD, FD_CLOEXEC)         = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7f12708) = -1 ENOMEM (Cannot allocate memory)
write(2, "Traceback (most recent call last"..., 35) = 35
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/agent."..., 52) = 52
open("/home/admin/sd-agent/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/daemon.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/home/admin/sd-agent/dae"..., 60) = 60
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/agent.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/agent."..., 54) = 54
open("/usr/lib/python2.4/sched.py", O_RDONLY|O_LARGEFILE) = 8
write(2, "  File \"/usr/lib/python2.4/sched"..., 55) = 55
fstat64(8, {st_mode=S_IFREG|0644, st_size=4054, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d28000
read(8, "\"\"\"A generally useful event sche"..., 4096) = 4054
write(2, "    ", 4)                     = 4
write(2, "void = action(*argument)\n", 25) = 25
close(8)                                = 0
munmap(0xb7d28000, 4096)                = 0
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/checks"..., 60) = 60
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/bin/sd-agent/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python24.zip/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/plat-linux2/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOMEM (Cannot allocate memory)
open("/usr/lib/python2.4/lib-tk/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/lib-dynload/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.4/site-packages/checks.py", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
write(2, "  File \"/usr/bin/sd-agent/checks"..., 64) = 64
open("/usr/lib/python2.4/subprocess.py", O_RDONLY|O_LARGEFILE) = 8
write(2, "  File \"/usr/lib/python2.4/subpr"..., 65) = 65
fstat64(8, {st_mode=S_IFREG|0644, st_size=39931, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d28000
read(8, "# subprocess - Subprocesses with"..., 4096) = 4096
read(8, "lso, the newlines attribute of t"..., 4096) = 4096
read(8, "code < 0:\n        print >>sys.st"..., 4096) = 4096
read(8, "alse does not exist on 2.2.0\ntry"..., 4096) = 4096
read(8, " p2cread\n        # c2pread    <-"..., 4096) = 4096
write(2, "    ", 4)                     = 4
write(2, "errread, errwrite)\n", 19)    = 19
close(8)                                = 0
munmap(0xb7d28000, 4096)                = 0
open("/usr/lib/python2.4/subprocess.py", O_RDONLY|O_LARGEFILE) = 8
write(2, "  File \"/usr/lib/python2.4/subpr"..., 71) = 71
fstat64(8, {st_mode=S_IFREG|0644, st_size=39931, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d28000
read(8, "# subprocess - Subprocesses with"..., 4096) = 4096
read(8, "lso, the newlines attribute of t"..., 4096) = 4096
read(8, "code < 0:\n        print >>sys.st"..., 4096) = 4096
read(8, "alse does not exist on 2.2.0\ntry"..., 4096) = 4096
read(8, " p2cread\n        # c2pread    <-"..., 4096) = 4096
read(8, "table(self, handle):\n           "..., 4096) = 4096
read(8, "rrno using _sys_errlist (or siml"..., 4096) = 4096
read(8, " p2cwrite = None, None\n         "..., 4096) = 4096
write(2, "    ", 4)                     = 4
write(2, "self.pid = os.fork()\n", 21)  = 21
close(8)                                = 0
munmap(0xb7d28000, 4096)                = 0
write(2, "OSError", 7)                  = 7
write(2, ": ", 2)                       = 2
write(2, "[Errno 12] Cannot allocate memor"..., 33) = 33
write(2, "\n", 1)                       = 1
unlink("/var/run/sd-agent.pid")         = 0
close(3)                                = 0
munmap(0xb7e0d000, 4096)                = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x589978}, {0xb89a60, [], SA_RESTORER, 0x589978}, 8) = 0
brk(0xa022000)                          = 0xa022000
exit_group(1)                           = ?
157701 次浏览

互换可能不是先前建议的那种转移注意力的做法。在 ENOMEM之前所讨论的 Python 进程有多大?

在内核2.6中,/proc/sys/vm/swappiness控制内核切换的积极性,而 overcommit*则通过一个眨眼和一个点头来文件内核可以分配多少内存以及多精确地分配内存。比如你的脸书感情状态 这很复杂

... 但是交换实际上是可以按需提供的(根据网站主机) ..。

但不是根据 free(1)命令的输出,free(1)命令没有显示服务器实例识别的交换空间。现在,您的 Web 主机可能比我更了解这个主题,但是我使用过的虚拟 RHEL/CentOS 系统已经报告了客户操作系统可用的交换机。

改编 红帽 KB 第15252条:

红帽企业 Linux 5系统 将在没有交换空间的情况下正常运行 只要是匿名的 内存和系统 V 共享内存是 小于内存总量的3/4。 内存不超过4GB 的系统 [建议] 2GB 的交换空间。

/proc/sys/vm设置与普通的 CentOS 5.3安装进行比较。添加交换文件。降下 swappiness看看你还能不能活下去。

Munmap (0xb7d28000,4096) = 0
写(2,“ OSERror”,7) = 7

我见过这样的草率代码:

serrno = errno;
some_Syscall(...)
if (serrno != errno)
/* sound alarm: CATROSTOPHIC ERROR !!! */

您应该检查这是否是在 只有当进行的系统调用 失败了。

编辑补充:

您没有说明这个过程的生存时间,可能是内存的消耗者

  • 分叉式过程
  • 未使用的数据结构
  • 共享库
  • 内存映射文件

我仍然怀疑您的客户/用户装载了某个内核模块或驱动程序 正在干扰 clone()系统调用(也许是一些模糊的安全增强, 类似于 LIDS 但是更加模糊?)或者以某种方式填充了一些内核数据 fork()/clone()操作所必需的结构(过程表,页 表、文件描述符表等)。

以下是 fork(2)手册页的相关部分:

ERRORS
EAGAIN fork() cannot allocate sufficient memory to copy the parent's page tables and allocate a task  structure  for  the
child.


EAGAIN It  was not possible to create a new process because the caller's RLIMIT_NPROC resource limit was encountered.  To
exceed this limit, the process must have either the CAP_SYS_ADMIN or the CAP_SYS_RESOURCE capability.


ENOMEM fork() failed to allocate the necessary kernel structures because memory is tight.

我建议用户在引导到一个普通的内核并且只加载了最少的模块和驱动程序集(运行应用程序/脚本所需的最少数量)之后尝试这种方法。从那里,假设它在该配置中工作,他们可以在该配置和显示该问题的配置之间执行二进制搜索。这是标准的系统管理员故障排除101。

您的 strace中的相关行是:

clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7f12708) = -1 ENOMEM (Cannot allocate memory)

我知道其他人已经讨论过交换和内存可用性(我建议你至少设置一个小的交换分区,讽刺的是,即使它在一个 RAM 磁盘上... ... Linux 内核中的代码路径,即使只有一点点可用的交换,也比那些没有可用交换的(异常处理路径)更广泛地运行。

然而我怀疑这仍然是一个障眼法。

事实上,free报告缓存和缓冲区使用的0(ZERO)内存是非常令人不安的。我怀疑 free的输出... ... 以及这里可能出现的应用程序问题,是由一些专有的内核模块引起的,这些内核模块以某种方式干扰了内存分配。

根据 fork ()/clone ()的手册页,如果调用会导致资源限制违规(RLIMIT _ NPROC) ,fork ()系统调用应该返回 EAGAIN... 但是,它没有说是否 EAGAIN 会被其他 RLIMIT * 违规返回。在任何情况下,如果您的目标/主机具有某种奇怪的 Vormeter 或其他安全设置(或者即使您的进程运行在某种奇怪的 SELinux 策略下) ,那么它可能会导致此-ENOMEM 故障。

这不太可能是一个普通的 Linux/UNIX 问题。

你有否尝试使用:

(status,output) = commands.getstatusoutput("ps aux")

我以为这也能解决我的问题。 但是后来我的进程被杀死了而不是没有产卵,这更糟糕。

经过一些测试,我发现这种情况只发生在旧版本的 python 上: 它发生在2.6.5上,而不是2.7

我的搜索引导我到这里 Python-close _ fds-problem,但不设置关闭 fds 并没有解决这个问题。它仍然很值得一读。

我发现 python 泄露文件描述符的方式就是盯着它:

watch "ls /proc/$PYTHONPID/fd | wc -l"

和您一样,我确实希望捕获命令的输出,也确实希望避免 OOM 错误... ... 但似乎唯一的办法是人们使用缺陷较少的 Python 版本。不太理想..。

作为一般规则(即在香草籽) ,fork/cloneENOMEM 特别发生失败,因为或者 clone0(dup_mmdup_task_structalloc_pidmpol_dupmm_init等呱呱叫) ,或者因为 security_vm_enough_memory_mm失败你 clone1

首先在 fork 尝试时检查未能进行 fork 的进程的 vmsize,然后比较与超额提交策略(插入数字)相关的可用内存量(物理内存和交换内存)

在您的特殊情况下,请注意 Virtuozzo 在 过度执法中有 额外支票。此外,我不确定从 内心您的容器对 交换和过度提交配置(为了影响执行的结果)真正拥有多少控制权

现在,为了真正向前推进,我会说你是 剩下两个选择:

  • 切换到更大的实例,或者
  • 更有效地控制脚本的内存内存中投入一些编码工作

请注意,如果结果证明不是您,而是其他人在您疯狂运行的同一台服务器上的不同实例中配置了不同的实例,那么所有的编码工作可能都是徒劳的。

在内存方面,我们已经知道 ABC0使用 ABC1/clone 在引擎盖下面,这意味着每次你调用它的时候,你是 再次请求巨蟒已经在消耗的内存,也就是在数百 MB 的额外,所有为了然后 exec一个微不足道的10kB 可执行文件,如 freeps。在不利的超额承诺策略的情况下,您将很快看到 ENOMEM

没有这个父页面表等复制问题的 fork的替代方案是 vfork0和 vfork1。但是如果你不想根据 vfork/posix_spawn重写 subprocess.Popen,可以考虑在脚本开始的时候(当 Python 的内存占用最小的时候)只使用一次 suprocess.Popenvfork2并行你的脚本; 轮询脚本的输出或者同步地读取它,如果你有其他的东西需要异步地处理,可能从一个单独的线程——用 Python 处理你的数据,但是把分叉的工作留给从属进程。

然而 ,在您的特殊情况下,您可以跳过调用 psfree; 那个 Python 中的信息可以直接从 < a href = “ http://www.kernel.org/doc/Document/filesystems/proc.txt”rel = “ noReferrer”> procfs 获得,无论您选择自己访问它还是通过 现有的图书馆及/或软件包。如果 psfree是您正在运行的唯一实用程序,那么您可以运行 完全去除 subprocess.Popen

最后,就 subprocess.Popen而言,无论您做什么,如果您的脚本泄漏了内存,您最终还是会碰壁。盯紧了,还有 检查内存泄漏

看看 free -m的输出,在我看来,您实际上没有可用的交换内存。我不确定在 Linux 中交换是否总是可以根据需要自动提供,但是我遇到了同样的问题,这里没有一个答案真正帮助了我。然而,添加一些交换内存,修复了我的问题,因为这可能帮助其他人面对同样的问题,我就如何添加一个1GB 的交换内存(在 Ubuntu 12.04上,但它应该工作在其他发行版类似)发表了我的答案

您可以首先检查是否启用了任何交换内存。

$sudo swapon -s

如果是空的,表示没有启用任何交换区。添加1GB 交换区:

$sudo dd if=/dev/zero of=/swapfile bs=1024 count=1024k
$sudo mkswap /swapfile
$sudo swapon /swapfile

将以下行添加到 fstab以使交换区永久化。

$sudo vim /etc/fstab


/swapfile       none    swap    sw      0       0

来源和更多的信息可以找到 给你

简单来说,你可以

echo 1 > /proc/sys/vm/overcommit_memory

如果确定系统具有足够的内存,请参见 Linux 优于提交启发式

也许你可以

$ sudo bash -c "echo vm.overcommit_memory=1 >> /etc/sysctl.conf"
$ sudo sysctl -p

对我的案子有用。

参考资料: https://github.com/openai/gym/issues/110#issuecomment-220672405