为什么我用这个python循环泄漏内存?

时间:2010-02-02 12:46:58

标签: python memory memory-leaks glob

我正在编写一个自定义文件系统爬虫,它通过sys.stdin传递数百万个glob进行处理。我发现在运行脚本时,它的内存使用量随着时间的推移而大量增加,整个事情几乎停止了。我在下面写了一个小例子来说明问题所在。我做错了什么,或者我在Python / glob模块中发现了一个错误? (我使用的是python 2.5.2)。


#!/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个对象,因此每100次迭代len(gc.get_objects()增加200。 len(gc.garbage)永远不会从0变化。第2代收集计数缓慢增加,而第0和第1计数则上下移动。

2 个答案:

答案 0 :(得分:6)

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

[1]:http://bugs.python.org/issue7846 Python Bug

答案 1 :(得分:2)

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

(注意我只是建议re.purge()来检查缓存是否会影响你的gc结果。在你的实际代码中没有必要这样做。)

我怀疑这可以解决你的大量内存增加问题。