Подтвердить что ты не робот

Почему я пропускаю память с помощью этого цикла питона?

Я пишу пользовательский искатель файловой системы, который получает миллионы глобусов для обработки через sys.stdin. Я нахожу, что при запуске script его использование памяти значительно увеличивается со временем, и все это сканируется практически до упора. Я написал минимальный случай, ниже которого показана проблема. Я что-то делаю неправильно, или я обнаружил ошибку в модуле 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 объектов освобождаются, поэтому len(gc.get_objects() увеличивается на 200 каждые 100 итераций. len(gc.garbage) никогда не изменяется от 0. Количество коллекций второго поколения увеличивается медленно, а 0-е и 1-е числа идут вверх и вниз.

4b9b3361

Ответ 1

Я проследил это до модуля fnmatch. glob.glob вызывает fnmatch, чтобы выполнить globbing, а fnmatch имеет кэш регулярных выражений, которые никогда не очищаются. Таким образом, в этом использовании кеш постоянно увеличивался и беспрепятственно. Я подал ошибку против библиотеки fnmatch [1].

[1]: http://bugs.python.org/issue7846 Ошибка Python

Ответ 2

Я не могу воспроизвести какие-либо фактические утечки в моей системе, но я думаю, что ваша "каждая 100-я итерация, 100 объектов освобождены", вы попадаете в кеш для скомпилированных регулярных выражений (через модуль glob). Если вы заглядываете в re.py, вы увидите, что _MAXCACHE по умолчанию - 100, и по умолчанию весь кеш удаляется, как только вы нажмете его (в _compile). Если вы вызываете re.purge() перед вашими вызовами gc, вы, вероятно, увидите, что эффект исчезнет.

(обратите внимание, что я предлагаю re.purge() здесь проверить, влияет ли кеш на ваши результаты gc. Не обязательно иметь это в вашем фактическом коде.)

Я сомневаюсь, что исправляет вашу проблему с увеличенной памятью.