【发布时间】:2010-11-16 01:14:17
【问题描述】:
注意:此问题已被重新提出,并提供了所有调试尝试的摘要here。
我有一个 Python 脚本作为后台进程运行,每 60 秒执行一次。其中一部分是调用subprocess.Popen 以获取ps 的输出。
ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE).communicate()[0]
运行几天后,调用出错:
文件“/home/admin/sd-agent/checks.py”,第 436 行,在 getProcesses 中 __init__ 中的文件“/usr/lib/python2.4/subprocess.py”,第 533 行 _get_handles 中的文件“/usr/lib/python2.4/subprocess.py”,第 835 行 OSError: [Errno 12] 无法分配内存但是free 在服务器上的输出是:
$免费-m 缓存的已用空闲共享缓冲区总数 内存:894 345 549 0 0 0 -/+ 缓冲区/缓存:345 549 交换:0 0 0我搜索了这个问题,发现 this article 上面写着:
解决方案是为您的服务器添加更多交换空间。当内核 fork 以启动建模器或发现进程时,它首先确保交换存储上有足够的可用空间,如果需要的话,新进程。
我注意到上面的免费输出中没有可用的交换。这是否可能是问题所在和/或可能有哪些其他解决方案?
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 找到,getProcesses 函数从第 442 行开始定义。从第 520 行开始,它由 doChecks() 调用。
【问题讨论】:
-
如果你运行top,你是否看到你的后台进程消耗更多的内存?鉴于它失败的代码,我会怀疑文件描述符是否用完(尽管这应该是不同的 errno)。你每 60 秒还在做什么?
-
在每次 Popen 调用前后记录了 free -m 的输出,内存保持不变。如何检查文件描述符?各种其他进程也正在启动,但它们也会被记录下来,并且内存不会随着时间的推移而“被用完”。
-
我用另一个建议更新了我的答案。