2010-02-02 12 views
12

Estoy escribiendo un rastreador de sistema de archivos personalizado, que pasa millones de globs para procesar a través de sys.stdin. Descubrí que cuando se ejecuta el script, su uso de memoria aumenta enormemente con el tiempo y todo se detiene prácticamente. He escrito un caso mínimo a continuación que muestra el problema. ¿Estoy haciendo algo mal o he encontrado un error en Python/el módulo glob? (Estoy usando Python 2.5.2).¿Por qué goteo la memoria con este ciclo de 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 

La salida se ve así:

 
(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) 

Cada iteración 100a, 100 objetos son liberados, por lo que len(gc.get_objects() aumenta en 200 cada 100 iteraciones. len(gc.garbage) nunca cambia de 0. El recuento de la colección de segunda generación aumenta lentamente, mientras que los recuentos 0º y 1º suben y bajan.

+1

Esto se acumula una gran cantidad de objetos no cobrados. Sin embargo, esto no se detiene, ¿o sí? ¿Puedes crear un pequeño script similar que realmente se detenga? –

Respuesta

2

No puedo reproducir ninguna fuga real en mi sistema, pero creo que "cada centésima iteración, se liberan 100 objetos" está presionando la caché para las expresiones regulares compiladas (a través del módulo glob). Si echas un vistazo a re.py verás que _MAXCACHE está predeterminado en 100, y de manera predeterminada, toda la memoria caché se dispara una vez que presionas eso (en _compile). Si llama al re.purge() antes de sus llamadas gc, probablemente verá que ese efecto desaparecerá.

(tenga en cuenta que sólo estoy sugiriendo re.purge() aquí para comprobar que la caché está afectando a los resultados de la cromatografía gaseosa. No debería ser necesario tener que en su código real.)

Dudo que solucione el problema masivo aumento de memoria aunque.

+0

Gracias por esto, cuando hice lo que sugirió, el efecto desapareció y los nuevos objetos por ciclo cambiaron a 2. No soluciona el problema de aumento de la memoria, pero ciertamente ayudará a comprender lo que está sucediendo. – Andy

6

Seguí esto hasta el módulo fnmatch. glob.glob llama a fnmatch para realizar realmente globbing, y fnmatch tiene un caché de expresiones regulares que nunca se borra. Entonces en este uso, el caché estaba creciendo continuamente y sin marcar. He archivado un error en la biblioteca fnmatch [1].

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

+0

¡Me pregunto cómo logré detectar el caché similar en el módulo re pero no en este! Tal vez debería restar un punto de mi propia respuesta por eso ... – mzz

Cuestiones relacionadas