我有一个Python脚本,它每60秒执行一次,作为后台进程运行。其中一部分是对subprocess.Popen的调用,以获取ps的输出。
ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE).communicate()[0]
运行几天后,该呼叫出现以下错误:
getProcesses中的文件“ /home/admin/sd-agent/checks.py”,行436 __init__中的文件“ /usr/lib/python2.4/subprocess.py”,第533行 _get_handles中的文件“ /usr/lib/python2.4/subprocess.py”,行835 OSError:[Errno 12]无法分配内存
但是,服务器上free的输出为:
$ free -m 已使用的可用共享缓冲区总数 内存:894345549549 0 0 0 -/ +缓冲区/缓存:345549 掉期: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
这是称为检查的较大类的一部分,该类在守护程序启动时初始化一次。
可以在http://github.com/dmytton/sd- agent/blob/82f5ff9203e54d2adeee8cfed704d09e3f00e8eb/checks.py中找到整个检查类,该类具有从442行定义的getProcesses函数。doChecks()从520行开始调用。
当您使用popen时,如果希望它关闭额外的文件描述符,则需要上交close_fds = True。
创建一个新管道,该管道出现在_get_handles函数中,从后向跟踪开始,它创建了2个文件描述符,但是您当前的代码永远不会关闭它们,并最终达到系统的最大fd限制。
不知道为什么收到的错误指示内存不足情况:它应该是文件描述符错误,因为的返回值pipe()有针对此问题的错误代码。
pipe()