2011-02-09 137 views
3

我有一个用python 2.6编写的程序,它创建了大量的短期实例(这是一个典型的生产者 - 消费者问题)。我注意到,top和pmap报告的内存使用量在创建这些实例时似乎会增加,并且永远不会回落。我担心我使用的一些python模块可能会泄漏内存,所以我仔细隔离了代码中的问题。然后,我尽可能以尽可能简短的方式重现它。我想出了这个:Python 2.6似乎GC清理对象,但内存不释放

class LeaksMemory(list): 
    timesDelCalled = 0 

    def __del__(self): 
     LeaksMemory.timesDelCalled +=1 


def leakSomeMemory(): 
    l = [] 
    for i in range(0,500000): 
     ml = LeaksMemory() 
     ml.append(float(i)) 
     ml.append(float(i*2)) 
     ml.append(float(i*3)) 
     l.append(ml) 

import gc 
import os 


leakSomeMemory() 

print("__del__ was called " + str(LeaksMemory.timesDelCalled) + " times") 
print(str(gc.collect()) +" objects collected") 
print("__del__ was called " + str(LeaksMemory.timesDelCalled) + " times") 
print(str(os.getpid()) + " : check memory usage with pmap or top") 

如果你运行这个的东西,如“python2.6的-i memoryleak.py”,它会中止,您可以使用pmap -x PID检查内存使用情况。我添加了del方法,所以我可以验证GC是否发生。这在我的实际程序中并不存在,似乎没有任何功能上的差异。每次调用leakSomeMemory()都会增加此程序消耗的内存量。我担心我会犯一些简单的错误,并且引用会被意外保存,但无法识别。

+0

如果等待一段时间,并在内存消耗回去了吗?我的理解是,Python从池中分配出来,所以如果它必须扩大池,它可能不会在将内存释放回池之后立即收缩。 – 2011-02-09 19:15:35

回答

8

Python将释放对象,但不会立即将内存释放回操作系统。相反,它将在相同的解释器中重复使用相同的分段以用于将来的分配。

这里有一个博客帖子有关的问题:http://effbot.org/pyfaq/why-doesnt-python-release-the-memory-when-i-delete-a-large-object.htm

更新:我测试了这个自己使用Python 2.6.4,并没有注意到在内存使用量持续增加。一些调用leakSomeMemory()导致Python进程的内存占用增加,并且一些使得它再次减少。所以这一切都取决于分配器如何重新使用内存。

4

根据Alex Martelli

“到 唯一真正可靠的方式确保一个大的内存,但临时使用 做了所有的资源返回 系统当它这样做,是有 使用发生在子进程中,其中 做需要内存的工作,然后 终止。“

因此,在您的情况下,听起来像使用multiprocessing模块在单独的进程中运行短期功能以确保在进程完成时返回资源是有意义的。

import multiprocessing as mp 

def NOT_leakSomeMemory(): 
    # do stuff 
    return result 


if __name__=='__main__': 
    pool = mp.Pool() 
    results=pool.map(NOT_leakSomeMemory, range(500000)) 

有关如何使用多设置的东西了,看到Doug Hellman's tutorial更多的想法: