【问题标题】:Why am I leaking memory with this python loop?为什么我用这个 python 循环泄漏内存?
【发布时间】:2011-01-12 03:32:09
【问题描述】:

我正在编写一个自定义文件系统爬虫,它通过 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) 这:4042,新:4042,Python 垃圾:0,Python 收集计数:(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() 每 100 次迭代增加 200。 len(gc.garbage) 永远不会从 0 变化。第 2 代收集计数缓慢增加,而第 0 和第 1 代计数上升和下降。

【问题讨论】:

  • 这积累了很多未收集的对象。然而,这并没有停止,不是吗?你能设计一个类似的小脚本,实际上会停止吗?

标签: python memory memory-leaks glob


【解决方案1】:

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

[1]:http://bugs.python.org/issue7846Python 错误

【讨论】:

  • 我想知道我是如何设法在 re 模块中发现类似的缓存,但不是这个!也许我应该从我自己的答案中减去一点......
【解决方案2】:

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

(请注意,我在这里仅建议 re.purge() 检查缓存是否影响了您的 gc 结果。在您的实际代码中应该没有必要。)

我怀疑这是否能解决您的大量内存增加问题。

【讨论】:

  • 谢谢你 - 当我按照你的建议做时,效果确实消失了,每个循环的新对象更改为 2。它不能解决内存增加问题,但肯定会帮助了解发生了什么。
猜你喜欢
  • 2012-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-10
  • 2015-08-04
  • 2016-08-03
相关资源
最近更新 更多