如何避免[Errno 12]无法分配使用子进程模块导致的内存错误

时间:2013-11-21 02:20:59

标签: python networking memory subprocess paramiko

完成工作测试用例

当然,根据您在本地和远程计算机上的内存,您的阵列大小会有所不同。

z1 = numpy.random.rand(300000000,2);
for i in range(1000):
  print('*******************************************\n'); 
  direct_output = subprocess.check_output('ssh blah@blah "ls /"', shell=True);
  direct_output = 'a'*1200000; 
  a2 = direct_output*10;
  print(len(direct_output));

当前用例

如果它有助于我的用例如下:

我发出数据库查询,然后将结果表存储在远程计算机上。然后我想通过网络传输它们并进行分析。到目前为止,我在python中做了类似下面的事情:

#run a bunch of queries before hand with the results in remote files

....
counter = 0
mergedDataFrame = None
while NotDone:
  output = subprocess.check_output('ssh blah@blah cat /data/file%08d'%(counter))
  data = pandas.read_csv(...)
  #do lots of analysis, append, merge, numpy stuff etc...
  mergedDataFrame = pandas.merge(...)
  counter += 1

在某些时候,我在check_output命令中收到以下错误:[Errno 12]无法分配内存

背景

感谢以下问题,我想我已经知道出了什么问题。发布了许多解决方案,我试图确定哪些解决方案将避免[Errno 12]无法使用fork / clone分配与子进程实现相关的内存错误。

Python subprocess.Popen "OSError: [Errno 12] Cannot allocate memory"这给出了基础诊断,并提出了一些解决方法,例如产生单独的脚本等......

Understanding Python fork and memory allocation errors建议使用rfoo绕过fork / clone的子进程限制并生成子进程和复制内存等......这似乎意味着客户端 - 服务器模型

What is the simplest way to SSH using Python?,但由于内存限制和fork / clone实现,我还有其他约束我无法使用子进程?解决方案建议使用paramiko或基于它构建的东西,其他建议使用subprocess(我发现它不适用于我的情况)。

还有其他类似问题,但答案经常谈到文件描述符是罪魁祸首(在这种情况下它们不是),向系统添加更多RAM(我不能这样做),升级到x64(我已经在x64上了) )。一些暗示ENOMEM的问题。一些答案提到了尝试确定subprocess.Popen(在我的情况下是check_output)是否没有正确清理进程,但看起来像S. Lott和其他人同意子进程代码本身正在正确清理。

我搜索了github https://github.com/paramiko/paramiko/search?q=Popen&type=Code上的源代码,似乎在proxy.py文件中使用了子进程。

实际问题

这是否意味着最终paramiko正在使用上面描述的Popen解决方案,当python内存占用增长并且由于clone / fork实现而重复Popen调用时会出现问题?

如果paramiko不起作用,还有另一种方法可以通过客户端解决方案来寻找我正在寻找的东西吗?或者是否需要客户端/服务器/套接字解决方案?如果是rfoo,tornado或zeromq中的任何一个,http转移在这里工作?

备注 我正在运行64位linux 8GB主内存。我不想追求购买更多内存的选择。

3 个答案:

答案 0 :(得分:50)

如果内存不足,您可能需要增加交换内存。或者您可能根本没有启用交换。在Ubuntu中(它也适用于其他发行版),您可以通过以下方式检查交换:

$sudo swapon -s

如果它为空,则表示您没有启用任何交换。添加1GB交换:

$sudo dd if=/dev/zero of=/swapfile bs=1024 count=1024k
$sudo mkswap /swapfile
$sudo swapon /swapfile

将以下行添加到fstab以使交换永久化。

$sudo vim /etc/fstab

     /swapfile       none    swap    sw      0       0 

可以找到来源和更多信息here

答案 1 :(得分:2)

如果你的内存不足,可能是因为子进程试图同时读入太多内存。除了使用重定向到本地文件之外,解决方案可能是使用类似popen的功能,并且可以从一次一点点读取stdin / stdout对。

答案 2 :(得分:1)

这应该这样做:

http://docs.python.org/3.3/library/subprocess.html#replacing-os-popen-os-popen2-os-popen3

这样,您可以一次读取行或块,而不是整个行。