使用subprocess.Popen时的Python内存分配错误

9 投票
4 回答
13159 浏览
提问于 2025-04-16 13:42

我正在做一些生物信息学的工作。我有一个Python脚本,其中有一部分会调用一个程序来进行一个耗费计算资源的过程(序列比对……这需要大量的计算能力和内存)。我使用subprocess.Popen来调用它。当我在一个测试案例上运行时,它完成得很好。但是,当我在完整文件上运行时,因为它需要对不同的输入集多次执行这个过程,就出现了问题,程序崩溃了。Subprocess抛出了:

OSError: [Errno 12] Cannot allocate memory

我找到了一些链接,讨论了类似的问题,分别在这里这里这里,但我不确定这些是否适用于我的情况。

默认情况下,序列比对程序会尝试请求51000M的内存。它并不总是会使用这么多,但有可能会。在加载和处理完整输入时,这么多内存是不可用的。然而,即使我限制它请求的内存量,或者尝试使用较低的可用内存,仍然会出现同样的错误。我也尝试过将shell设置为True,但结果一样。

这个问题困扰了我几天了。谢谢大家的帮助。

编辑:扩展一下错误追踪信息:

File "..../python2.6/subprocess.py", line 1037, in _execute_child
    self.pid=os.fork()
OSError: [Errno 12] Cannot allocate memory

抛出了这个错误。

编辑2:在64位的Ubuntu 10.4上运行Python 2.6.4

4 个回答

0

我建议在64位的操作系统上运行64位的Python。

如果你用的是32位的系统,实际上你只能使用大约3GB的内存,之后系统就会告诉你不能再用了。

另外一个选择是使用内存映射文件来打开文件:

http://docs.python.org/library/mmap.html

补充:哦,你是在用64位的系统……可能的原因是你的内存和交换空间都用完了……解决办法可能是增加交换空间的大小。

0

这跟Python或者subprocess模块没有关系。subprocess.Popen只是把它从操作系统那里收到的错误信息告诉你。顺便问一下,你用的是什么操作系统呢?在Linux上可以查阅man 2 fork的内容:

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

你是不是多次调用了subprocess.Popen?如果是这样的话,最好的办法就是确保在下一次调用之前,前一次的进程已经结束并被清理掉。

16

我真的很同情提问者。六年过去了,居然没有人提到这是Unix中一个非常常见的问题,实际上和python或生物信息学没有关系。当你调用os.fork()时,父进程的内存会暂时翻倍(因为子进程需要访问父进程的内存),然后再把这些内存丢掉,去执行exec()。虽然这部分内存不一定会被实际复制,但系统必须有足够的内存来支持这种复制。因此,如果你的父进程使用的内存超过了系统内存的一半,即使你只是执行“wc -l”这样的简单命令,也会遇到内存错误。

解决办法是使用posix_spawn,或者在脚本开始时创建所有的子进程,这样内存使用量较低,然后在父进程完成内存密集型操作后再使用这些子进程。

如果你在谷歌上搜索“os.fork”和“memory”这两个关键词,会找到几个相关的Stack Overflow帖子,能进一步解释发生了什么哦 :)

撰写回答