Python多进程内存增加

gos*_*som 2 python memory multiprocessing

我有一个应该永远运行的程序.这是我在做的事情:

from myfuncs import do, process

class Worker(multiprocessing.Process):

    def __init__(self, lock):
        multiprocesing.Process.__init__(self)
        self.lock = lock
        self.queue = Redis(..) # this is a redis based queue
        self.res_queue = Redis(...)

     def run():
         while True:
             job = self.queue.get(block=True)
             job.results = process(job)
             with self.lock:
                 post_process(self.res_queue, job)


def main():
    lock = multiprocessing.Semaphore(1)
    ps = [Worker(lock) for _ in xrange(4)]
    [p.start() for p in ps]
    [p.join() for p in ps]
Run Code Online (Sandbox Code Playgroud)

self.queue和self.res_queue是两个与python stdlib Queue类似的对象,但它们使用Redis数据库作为后端.

函数进程对作业所承载的数据(主要是html解析)进行一些处理并返回字典.

函数post_process通过检查某些条件将作业写入另一个redis队列(一次只有一个进程可以检查锁定原因的条件).它返回True/False.

该程序每天使用的内存正在增加.有人可以弄清楚发生了什么吗?

当运行方法中的作业超出范围时,内存应该是免费的吗?

aba*_*ert 5

当运行方法中的作业超出范围时,内存应该是免费的吗?

首先,范围是整个run方法,它永远循环,所以永远不会发生.(此外,退出run方法时,进程关闭,无论如何都释放了内存......)

但即使它确实超出范围,这也不意味着你认为它意味着什么.Python不像C++,其中存在存储在堆栈中的变量.所有对象都存在于堆上,并且它们保持活动状态,直到不再有对它们的引用为止.超出范围的变量意味着变量不再引用它曾经引用的任何对象.如果该变量是对象的唯一引用,则它将被释放*,但如果您在其他地方有其他引用,则在其他引用消失之前,不能释放该对象.

与此同时,超出范围并没有什么神奇之处.变量停止引用对象的任何方式都具有相同的效果 - 无论是变量超出范围,是否调用del它,或者为其分配新值.因此,每次循环,当你这样做时job =,你就会删除之前的引用,job即使没有任何东西超出范围.(但请记住,您将有两个工作在高峰时段,而不是一个,因为新的工作在旧的工作被释放之前被拉出队列.如果这是一个问题,您可以job = None在阻塞队列之前一直做.)

因此,假设问题实际上是job对象(或它拥有的东西),问题是你没有向我们展示的一些代码是在某处保留对它的引用.

在不知道你在做什么的情况下,很难建议修复.它可能只是"不存储那里".或者它可能是"存储weakref而不是对象本身".或者"添加LRU算法".或者"添加一些流量控制,这样如果你得到太多备份,你就不会继续工作,直到你的内存耗尽".


*在CPython中,这会立即发生,因为垃圾收集器基于引用计数.另一方面,在Jython和IronPython中,垃圾收集器只依赖于底层VM的垃圾收集器,因此在JVM或CLR注意到它不再被引用之前,该对象不会被释放,这通常不是立即的,并且是不确定的.

  • @gosom:CPython确实几乎不会释放操作系统的内存,所以如果你的内存使用率达到峰值,那么这个峰值将是你的内存使用量,直到你退出.但是,至少在64位的土地上,这通常不是问题; 如果那个额外的内存永远不会被触及,而且任何其他进程都需要它,它就会被换掉并且从不换回来,所以你真的只是浪费1MB的页面空间而不是12GB的活动内存.因此,如果您认为这是正在发生的事情,请确保问题影响性能或稳定性,然后再浪费太多调试时间...... (2认同)
  • 无论如何,如果你真的_are_保留垃圾,这可能是一个更大的问题,只是保留堆的未使用的页面.如果你需要调试它,Python有一些工具来帮助这样做,比如`gc`模块和(用3.4+)`tracemalloc`,并且有很多第三方Python模块和外部工具也可以提供帮助.除非你的工作对象随着时间的推移逐渐变大,否则"多处理"本身就会出现漏洞,你会在某处保留一些东西. (2认同)