2009-02-18 4 views
7

Sembra che il mio programma abbia perdite di handle di file. Come posso sapere dove?Rileva il file che gestisce le perdite in python?

Il mio programma utilizza gli handle di file in alcuni punti diversi, in uscita da processi figlio, chiama ctypes API (ImageMagick) apre i file e vengono copiati.

Si blocca in shutil.copyfile, ma sono abbastanza sicuro che questo non è il posto che perde.

Traceback (most recent call last): 
    File "<string>", line 1, in <module> 
    File "C:\Python25\Lib\site-packages\magpy\magpy.py", line 874, in main 
    magpy.run_all() 
    File "C:\Python25\Lib\site-packages\magpy\magpy.py", line 656, in run_all 
    [operation.operate() for operation in operations] 
    File "C:\Python25\Lib\site-packages\magpy\magpy.py", line 417, in operate 
    output_file = self.place_image(output_file) 
    File "C:\Python25\Lib\site-packages\magpy\magpy.py", line 336, in place_image 
    shutil.copyfile(str(input_file), str(self.full_filename)) 
    File "C:\Python25\Lib\shutil.py", line 47, in copyfile 
    fdst = open(dst, 'wb') 
IOError: [Errno 24] Too many open files: 'C:\\Documents and Settings\\stuart.axon\\Desktop\\calzone\\output\\wwtbam4\\Nokia_NCD\\nl\\icon_42x42_V000.png' 
Press any key to continue . . . 
+0

Non proprio una risposta, ma se stai usando Python 2.5 o più recente, cerca nella parola chiave "with" che può chiudere automaticamente i file per te una volta che hai finito con loro. –

risposta

3

Guardate uscita dal ls -l /proc/$pid/fd/ (sostituendo il PID del processo, naturalmente) per vedere quali file sono aperti [o, su Win32, utilizzare Process Explorer per elencare i file aperti]; quindi scopri dove nel tuo codice li stai aprendo e fai in modo che venga chiamato close(). (Sì, il garbage collector finirà per chiudere le cose, ma non è sempre abbastanza veloce per evitare di rimanere senza fds).

Anche il controllo di eventuali riferimenti circolari che potrebbero impedire la raccolta dei dati inutili è una buona pratica. (Il collettore di cicli alla fine li eliminerà - ma potrebbe non funzionare abbastanza frequentemente per evitare l'esaurimento del descrittore di file: sono stato morso personalmente da questo).

+0

Suppongo che sia una casella win32, dati i percorsi c: \ python25. – twk

+0

Garbage collection: Python non ha qualcosa come il cycle collector in alcune implementazioni js? –

+0

@Stuart - È un GC conteggio di riferimento con un raccoglitore di cicli, ma il raccoglitore di cicli non viene eseguito abbastanza frequentemente per chiudere necessariamente oggetti file senza riferimento prima che la RAM si esaurisca. –

3

Utilizzare Process Explorer, selezionare il processo, Visualizza-> Vista riquadro inferiore-> Maniglie - quindi cercare ciò che sembra fuori posto, in genere molti file uguali o simili aprono i punti del problema.

3

lsof -p <process_id> funziona bene su diversi sistemi simili a UNIX incluso FreeBSD.

+0

Ovviamente la domanda riguarda Windows. – Olli

3

Ho avuto problemi simili, a corto di descrittori di file durante le chiamate subprocess.Popen(). Ho usato il seguente script per eseguire il debug su quanto sta accadendo:

import os 
import stat 

_fd_types = (
    ('REG', stat.S_ISREG), 
    ('FIFO', stat.S_ISFIFO), 
    ('DIR', stat.S_ISDIR), 
    ('CHR', stat.S_ISCHR), 
    ('BLK', stat.S_ISBLK), 
    ('LNK', stat.S_ISLNK), 
    ('SOCK', stat.S_ISSOCK) 
) 

def fd_table_status(): 
    result = [] 
    for fd in range(100): 
     try: 
      s = os.fstat(fd) 
     except: 
      continue 
     for fd_type, func in _fd_types: 
      if func(s.st_mode): 
       break 
     else: 
      fd_type = str(s.st_mode) 
     result.append((fd, fd_type)) 
    return result 

def fd_table_status_logify(fd_table_result): 
    return ('Open file handles: ' + 
      ', '.join(['{0}: {1}'.format(*i) for i in fd_table_result])) 

def fd_table_status_str(): 
    return fd_table_status_logify(fd_table_status()) 

if __name__=='__main__': 
    print fd_table_status_str() 

È possibile importare questo modulo e chiamare fd_table_status_str() registrare lo stato tabella di descrittore di file in diversi punti nel codice.

Inoltre, assicurarsi che le istanze di sottoprocesso.Popen siano distrutte. Mantenere i riferimenti delle istanze Popen in Windows impedisce l'esecuzione del GC. E se le istanze vengono mantenute, le pipe associate non vengono chiuse. Maggiori informazioni here.

+0

"Inoltre, assicurati che le istanze subprocess.Popen siano distrutte.Tenere i riferimenti delle istanze Popen in Windows impedisce al GC di essere in esecuzione e, se le istanze vengono mantenute, le pipe associate non vengono chiuse.Ulteriori informazioni" - questo è un motivo particolare per il subjuct nel mio caso. Lo risolviamo tramite pOpenInstansec [index] = None - per risolvere tutti gli handle relativi al processo creato (come stdin \ etc.) – N0dGrand87