Python subprocess.Popen 错误与 OSError: [Errno 12] 一段时间后无法分配内存 [英] Python subprocess.Popen erroring with OSError: [Errno 12] Cannot allocate memory after period of time

查看:39
本文介绍了Python subprocess.Popen 错误与 OSError: [Errno 12] 一段时间后无法分配内存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:此问题已重新提出,并附有所有调试尝试的摘要此处.

<小时>

我有一个 Python 脚本,它作为每 60 秒执行一次的后台进程运行.其中一部分是调用 subprocess.Popen 以获取 ps.

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

运行几天后,调用出错:

<前>getProcesses 中的文件/home/admin/sd-agent/checks.py",第 436 行文件/usr/lib/python2.4/subprocess.py",第 533 行,在 __init__ 中文件/usr/lib/python2.4/subprocess.py",第 835 行,在 _get_handles 中OSError: [Errno 12] 无法分配内存

但是 free 在服务器上的输出是:

<前>$免费 -m缓存的已用空闲共享缓冲区总数内存:894 345 549 0 0 0-/+ 缓冲区/缓存:345 549交换:0 0 0

我四处寻找问题,发现 这篇文章 说:

解决方案是为您的服务器添加更多交换空间.当内核分叉启动建模器或发现进程时,它首先确保交换存储新进程(如果需要)上有足够的可用空间.

我注意到上面的免费输出没有可用的交换.这可能是问题所在和/或可能有其他解决方案吗?

2009 年 8 月 13 日更新 上面的代码每 60 秒调用一次,作为一系列监控功能的一部分.该过程是守护进程并使用 sched 安排检查.上述函数的具体代码为:

def getProcesses(self):self.checksLogger.debug('getProcesses: start')# 内存记录(案例 27152)如果 self.agentConfig['debugMode'] 和 sys.platform == 'linux2':mem = subprocess.Popen(['free', '-m'], stdout=subprocess.PIPE).communicate()[0]self.checksLogger.debug('getProcesses: Popen 前的内存 - ' + str(mem))# 获取ps的输出尝试:self.checksLogger.debug('getProcesses: 尝试 Popen')ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE).communicate()[0]除了例外,e:导入回溯self.checksLogger.error('getProcesses: exception = ' + traceback.format_exc())返回错误self.checksLogger.debug('getProcesses: Popen 成功,解析')# 内存记录(案例 27152)如果 self.agentConfig['debugMode'] 和 sys.platform == 'linux2':mem = subprocess.Popen(['free', '-m'], stdout=subprocess.PIPE).communicate()[0]self.checksLogger.debug('getProcesses: memory after Popen - ' + str(mem))# 拆分每个进程processLines = ps.split('
')del processLines[0] # 删除标题processLines.pop() # 删除尾随的空行进程 = []self.checksLogger.debug('getProcesses: Popen 成功,解析,循环')对于 processLines 中的行:line = line.split(None, 10)进程.附加(行)self.checksLogger.debug('getProcesses: 完成,返回')退货流程

这是一个名为检查的更大类的一部分,它在守护进程启动时初始化一次.

可以在 http://github.com/dmytton/sd-agent/blob/82f5ff9203e54d2adeee8cfed704d09e3f00e8eb/checks.py 使用从第 442 行定义的 getProcesses 函数.这由 doChecks() 从第 520 行开始调用.

解决方案

当你使用 popen 时,如果你想让它关闭额外的文件描述符,你需要提交 close_fds=True .

创建一个新管道,它发生在 _get_handles 函数中的回溯,创建了 2 个文件描述符,但是您当前的代码永远不会关闭它们,并且您最终会达到系统最大 fd 限制.

不知道为什么您收到的错误表示内存不足:它应该是文件描述符错误,因为 pipe() 的返回值具有针对此问题的错误代码.

Note: This question has been re-asked with a summary of all debugging attempts here.


I have a Python script that is running as a background process executing every 60 seconds. Part of that is a call to subprocess.Popen to get the output of ps.

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

After running for a few days, the call is erroring with:

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

However the output of free on the server is:

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

I have searched around for the problem and found this article which says:

Solution is to add more swap space to your server. When the kernel is forking to start the modeler or discovery process, it first ensures there's enough space available on the swap store the new process if needed.

I note that there is no available swap from the free output above. Is this likely to be the problem and/or what other solutions might there be?

Update 13th Aug 09 The code above is called every 60 seconds as part of a series of monitoring functions. The process is daemonized and the check is scheduled using sched. The specific code for the above function is:

def getProcesses(self):
    self.checksLogger.debug('getProcesses: start')

    # Memory logging (case 27152)
    if self.agentConfig['debugMode'] and sys.platform == 'linux2':
        mem = subprocess.Popen(['free', '-m'], stdout=subprocess.PIPE).communicate()[0]
        self.checksLogger.debug('getProcesses: memory before Popen - ' + str(mem))

    # Get output from ps
    try:
        self.checksLogger.debug('getProcesses: attempting Popen')

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

    except Exception, e:
        import traceback
        self.checksLogger.error('getProcesses: exception = ' + traceback.format_exc())
        return False

    self.checksLogger.debug('getProcesses: Popen success, parsing')

    # Memory logging (case 27152)
    if self.agentConfig['debugMode'] and sys.platform == 'linux2':
        mem = subprocess.Popen(['free', '-m'], stdout=subprocess.PIPE).communicate()[0]
        self.checksLogger.debug('getProcesses: memory after Popen - ' + str(mem))

    # Split out each process
    processLines = ps.split('
')

    del processLines[0] # Removes the headers
    processLines.pop() # Removes a trailing empty line

    processes = []

    self.checksLogger.debug('getProcesses: Popen success, parsing, looping')

    for line in processLines:
        line = line.split(None, 10)
        processes.append(line)

    self.checksLogger.debug('getProcesses: completed, returning')

    return processes

This is part of a bigger class called checks which is initialised once when the daemon is started.

The entire checks class can be found at http://github.com/dmytton/sd-agent/blob/82f5ff9203e54d2adeee8cfed704d09e3f00e8eb/checks.py with the getProcesses function defined from line 442. This is called by doChecks() starting at line 520.

解决方案

when you use popen you need to hand in close_fds=True if you want it to close extra file descriptors.

creating a new pipe, which occurs in the _get_handles function from the back trace, creates 2 file descriptors, but your current code never closes them and your eventually hitting your systems max fd limit.

Not sure why the error you're getting indicates an out of memory condition: it should be a file descriptor error as the return value of pipe() has an error code for this problem.

这篇关于Python subprocess.Popen 错误与 OSError: [Errno 12] 一段时间后无法分配内存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆