在我开发的应用程序中,我使用multiprocessing.BaseManager
与主进程并行执行一些繁重复杂的计算。我使用管理器而不是池,因为这些计算是作为class
实现的,只需要偶尔执行一次。在
每次我在管理器中创建计算类的新实例时,调用其方法,获取结果,然后删除实例并调用gc.收集()在经理那里。在
下面是一个伪代码来演示这种情况:
import gc
from multiprocessing.managers import BaseManager
class MyComputer(object):
def compute(self, args):
#several steps of computations
return huge_list
class MyManager(BaseManager): pass
MyManager.register('MyComputer', MyComputer)
MyManager.register('gc_collect', gc.collect)
if __name__ == '__main__':
manager = MyManager()
manager.start()
#obtain args_list from the configuration file
many_results = []
for args in args_list:
comp = manager.MyComputer()
many_results.append(comp.compute(args))
del comp
manager.gc_collect()
#do somthing with many_results
计算结果很大(200Mb-600Mb)。问题是:根据top
,管理进程使用的驻留内存在一次计算后显著增长(50Mb到1Gb)。如果在所有计算中使用一个comp
对象,或者没有调用manager.gc_collect()
,它的增长速度会更快。所以我想这个对象确实被删除了,垃圾回收器也在工作,但是仍然有一些东西被留下。在
下面是管理器进程在五轮计算中使用的驻留内存的图:http://i.imgur.com/BY6KuXD.png
我的问题是:
经过一个多星期的研究,我回答了自己的问题:
调查的另一个重要结论是:
注意这些巨大的内存峰值(http://i.imgur.com/BY6KuXD.png)。它们比产生的任何结果(约250Mb)大得多。事实证明,这是因为他们是在腌制过程中未经腌制而成的。酸洗是一个非常耗时的过程;它的内存使用量与要酸洗的对象的大小呈非线性关系。因此,如果你(不)腌制一个~10Mb大的对象,它将使用~12-13Mb,但(un)酸洗~250Mb则需要800-1000Mb!因此,为了提取一个大对象(,其中包括管道、队列、连接、托架等的任何用法,),您需要以某种方式序列化该过程。在
很难猜出是什么问题。因为内存泄漏总是很难找到。 如果您没有memory_profiler,我建议您安装memory_profiler。它可以帮助你很容易地找到记忆问题。在
只是一个如何使用它的例子:
在测试.py
如您所见,我向我怀疑有内存问题的函数添加了
^{pr2}$@profile
装饰器。 然后按如下方式运行脚本:结果是:
从这个输出可以很容易地看出哪一行占用了大量内存。在
相关问题 更多 >
编程相关推荐