2010-02-02 16 views
12

Sto scrivendo un crawler di file system personalizzato, che riceve milioni di glob da elaborare tramite sys.stdin. Sto scoprendo che durante l'esecuzione della sceneggiatura, il suo utilizzo della memoria aumenta in modo massiccio nel tempo e l'intera struttura si ferma praticamente all'arresto. Ho scritto un caso minimale sotto il quale mostra il problema. Sto facendo qualcosa di sbagliato, o ho trovato un bug in Python/il modulo glob? (Sto usando python 2.5.2).Perché sto perdendo memoria con questo loop 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 

Il risultato è simile:

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

Ogni iterazione 100, 100 oggetti vengono liberati, così len(gc.get_objects() aumenta di 200 ogni 100 iterazioni. len(gc.garbage) non cambia mai da 0. Il conteggio delle raccolte di 2a generazione aumenta lentamente, mentre i conteggi 0 ° e 1 ° aumentano e diminuiscono.

+1

Questo si accumula un sacco di oggetti non ritirati. Tuttavia, questo non rallenta fino a fermarsi, vero? Riesci a elaborare un piccolo script simile che in realtà si ferma? –

risposta

2

Non riesco a riprodurre alcuna perdita effettiva sul mio sistema, ma penso che "ogni 100 ° iterazione, 100 oggetti vengono liberati" stai colpendo la cache per le espressioni regolari compilate (tramite il modulo glob). Se sbirci a re.py vedrai il valore predefinito di _MAXCACHE su 100 e, per impostazione predefinita, l'intera cache viene spazzata via una volta che lo hai colpito (in _compile). Se chiami re.purge() prima delle tue chiamate su gc probabilmente vedrai l'effetto scomparire.

(nota Sto solo suggerendo re.purge() qui per verificare che la cache sta interessando i risultati gc. Non dovrebbe essere necessario avere che nel codice vero e proprio.)

dubito che risolve il massiccio aumento di memoria problema anche se.

+0

Grazie per questo - quando ho fatto quello che mi hai suggerito, l'effetto in effetti è andato via, e i nuovi oggetti per ciclo sono cambiati in 2. Non risolve il problema di aumento di memoria, ma sicuramente aiuterà a capire cosa sta succedendo. – Andy

6

L'ho rintracciato nel modulo fnmatch. glob.glob chiama fnmatch per eseguire effettivamente il globbing e fnmatch ha una cache di espressioni regolari che non viene mai cancellata. Quindi, in questo utilizzo, la cache cresceva continuamente e non controllata. Ho registrato un errore nella libreria fnmatch [1].

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

+0

Mi chiedo come sia riuscita ad individuare la cache simile nel modulo re ma non questa! Forse dovrei sottrarre un punto dalla mia risposta per quello ... – mzz

Problemi correlati