2010-02-02 73 views
12

我正在写一个自定义的文件系统爬虫,它通过了sys.stdin来处理数以百万计的球。我发现,在运行脚本时,随着时间的推移,其内存使用量会大量增加,整个事情几乎都会停止。我写了一个小问题,下面显示了这个问题。我做错了什么,或者我在Python/glob模块中发现了一个错误? (我正在使用python 2.5.2)。为什么我用这个python循环泄漏内存?


#!/usr/bin/env python 
import glob 
import sys 
import gc 

previous_num_objects = 0 

for count, line in enumerate(sys.stdin): 
    glob_result = glob.glob(line.rstrip('\n')) 
    current_num_objects = len(gc.get_objects()) 
    new_objects = current_num_objects - previous_num_objects 

    print "(%d) This: %d, New: %d, Garbage: %d, Collection Counts: %s"\ 
% (count, current_num_objects, new_objects, len(gc.garbage), gc.get_count()) 
    previous_num_objects = current_num_objects 

输出看起来像:

 
(0) This: 4042, New: 4042, Python Garbage: 0, Python Collection Counts: (660, 5, 0) 
(1) This: 4061, New: 19, Python Garbage: 0, Python Collection Counts: (90, 6, 0) 
(2) This: 4064, New: 3, Python Garbage: 0, Python Collection Counts: (127, 6, 0) 
(3) This: 4067, New: 3, Python Garbage: 0, Python Collection Counts: (130, 6, 0) 
(4) This: 4070, New: 3, Python Garbage: 0, Python Collection Counts: (133, 6, 0) 
(5) This: 4073, New: 3, Python Garbage: 0, Python Collection Counts: (136, 6, 0) 
(6) This: 4076, New: 3, Python Garbage: 0, Python Collection Counts: (139, 6, 0) 
(7) This: 4079, New: 3, Python Garbage: 0, Python Collection Counts: (142, 6, 0) 
(8) This: 4082, New: 3, Python Garbage: 0, Python Collection Counts: (145, 6, 0) 
(9) This: 4085, New: 3, Python Garbage: 0, Python Collection Counts: (148, 6, 0) 

每第100次迭代,100个对象被释放,所以len(gc.get_objects()增加了200每100次迭代。 len(gc.garbage)决不会从0开始变化。第2代收集计数缓慢增加,而第0和第1个计数增加和减少。

+1

此积累了很多未收集的对象。但是,这并没有停下来,是吗?你能制作一个类似的小脚本,实际上是爬行停下来的吗? – 2010-02-02 12:51:24

回答

2

我不能在系统上重现任何实际的泄漏,但我认为你的“每100次迭代,100个对象被释放”,你是否正在编译正则表达式的缓存(通过glob模块)。如果您查看re.py,您会看到_MAXCACHE默认为100,默认情况下,一旦您点击该缓存(在_compile),整个缓存就会被吹走。如果您在拨打gc电话前致电re.purge(),您可能会看到效果消失。

(请注意,我只是建议re.purge()这里检查缓存影响您GC的结果。它不应该是需要有在您的实际代码。)

我怀疑修复您的海量内存增加的问题虽然。

+0

感谢您 - 当我按照您的建议做时,效果确实消失了,每个循环的新对象更改为2.它不能解决内存增加问题,但它肯定有助于理解正在发生的事情。 – Andy 2010-02-02 17:21:10

6

我跟踪到了这个fnmatch模块。 glob.glob调用fnmatch来实际执行globbing,而fnmatch有一个永远不会被清除的正则表达式缓存。因此,在这种使用中,缓存不断增长并且未经检查。我已经提交了一个针对fnmatch库的错误[1]。

[1]:http://bugs.python.org/issue7846 Python的错误

+0

我想知道我是如何设法发现re模块中的类似缓存,但不是这个!也许我应该从我自己的答案中减去一点...... – mzz 2010-02-04 00:53:34