Python subprocess.Popen错误与OSError:[Errno 12]一段时间后无法分配内存

Dav*_*idM 10 python linux memory

注意:此问题已通过此处的所有调试尝试的摘要重新询问.


我有一个Python脚本作为后台进程运行,每60秒执行一次.部分原因是调用subprocess.Popen来获取ps的输出.

ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE).communicate()[0]
Run Code Online (Sandbox Code Playgroud)

运行几天后,调用错误:

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输出是:

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

我一直在寻找这个问题,并发现这篇文章说:

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

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

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

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('\n')

    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
Run Code Online (Sandbox Code Playgroud)

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

整个检查类可以在http://github.com/dmytton/sd-agent/blob/82f5ff9203e54d2adeee8cfed704d09e3f00e8eb/checks.py中找到,其中getProcesses函数是从442行定义的.这是由doChecks()从第520行开始调用的.

pil*_*row 5

你可能有一个内存泄漏受到你的python脚本继承的一些资源限制(RLIMIT_DATA,RLIMIT_AS?)的限制.在运行脚本之前检查*ulimit(1)*s,并像其他人建议的那样分析脚本的内存使用情况.

ps在您向我们展示的代码段后,您如何处理变量? 你是否一直提到它,永远不会被释放?引用subprocess模块文档:

注意:读取的数据缓冲在内存中,因此如果数据大小很大或不受限制,请不要使用此方法.

...和ps aux在繁忙的系统上可能很冗长......

更新

您可以使用资源模块使用python脚本检查rlimits :

import resource
print resource.getrlimit(resource.RLIMIT_DATA) # => (soft_lim, hard_lim)
print resource.getrlimit(resource.RLIMIT_AS)
Run Code Online (Sandbox Code Playgroud)

如果这些返回"无限制" - (-1, -1)- 那么我的假设是不正确的,你可以继续前进!

另见resource.getrusage,尤其是 这些ru_??rss字段可以帮助您使用python脚本检测内存消耗,而不需要外部程序.


Mar*_*ark 3

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

创建一个新管道(发生在来自后台跟踪的 _get_handles 函数中)会创建 2 个文件描述符,但您当前的代码永远不会关闭它们,并且最终会达到系统最大 fd 限制。

不确定为什么您收到的错误表明内存不足:它应该是文件描述符错误,因为 的返回值pipe()具有此问题的错误代码。

  • 这并没有解决问题。我在 http://stackoverflow.com/questions/1367373/python-subprocess-popen-oserror-errno-12-cannot-allocate-memory 重新发布了问题 (2认同)