2009-02-18 20 views
7

Parece que mi programa está perdiendo identificadores de archivo. ¿Cómo puedo averiguar dónde?¿Detecta fugas de identificador de archivo en python?

Mi programa utiliza identificadores de archivo en algunos lugares diferentes: salida de procesos secundarios, llame al ctypes API (ImageMagick) abre archivos y los copia.

Se bloquea en shutil.copyfile, pero estoy bastante seguro de que este no es el lugar donde se está filtrando.

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

No es toda una respuesta, pero si está utilizando Python 2.5 o posterior, busque en la palabra clave "con" que puede cerrar automáticamente los archivos una vez que haya terminado con ellos. –

Respuesta

3

mirada a la salida de ls -l /proc/$pid/fd/ (sustituyendo el PID de su proceso, por supuesto) para ver qué archivos están abiertos [o, en Win32, utilice Process Explorer a la lista de archivos abiertos]; luego averigua en qué parte de tu código los estás abriendo y haz que se llame al close(). (Sí, el recolector de basura eventualmente cerrará las cosas, pero no siempre es lo suficientemente rápido para evitar quedarse sin fds).

También es una buena práctica verificar las referencias circulares que podrían estar impidiendo la recolección de basura. (Eventualmente, el recolector de ciclos se deshará de estos, pero es posible que no se ejecute con la frecuencia suficiente como para evitar el agotamiento del descriptor de archivos; me ha picado esto personalmente).

+0

Supongo que es un cuadro win32, dadas las rutas c: \ python25. – twk

+0

Recolección de basura: ¿Python no tiene algo así como el recolector de ciclos en algunas implementaciones js? –

+0

@ Stuart: es un GC contado de referencia con un colector de ciclos, pero el colector de ciclos no se ejecuta con la frecuencia suficiente para cerrar necesariamente objetos de archivos sin referencia antes de que se agote la RAM. –

3

Use Process Explorer, seleccione su proceso, Ver-> Vista del panel inferior-> Manijas: luego, busque lo que parece fuera de lugar: por lo general, muchos archivos iguales o similares abren puntos al problema.

3

lsof -p <process_id> funciona bien en varios sistemas tipo UNIX, incluido FreeBSD.

+0

Obviamente, la pregunta es sobre Windows. – Olli

3

Tuve problemas similares, quedándome sin descriptores de archivos durante las llamadas de subproceso.Popen(). He utilizado la siguiente secuencia de comandos para depurar sobre lo que está ocurriendo:

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

Puede importar este módulo y llamar fd_table_status_str() para registrar el estado de la tabla de descriptores de archivos en diferentes puntos en el código.

Además, asegúrese de que las instancias de subproceso.Popen se destruyan. Mantener las referencias de las instancias de Popen en Windows impide que el GC se ejecute. Y si se mantienen las instancias, las tuberías asociadas no se cierran. Más información here.

+0

"Además, asegúrese de que las instancias de subproceso.Popen se destruyan. Mantener las referencias de las instancias de Popen en Windows impide que el GC se ejecute. Y si las instancias se mantienen, las tuberías asociadas no se cierran. Más información" - esta es una razón particular para el subjunt en mi caso. Lo resolvemos a través de pOpenInstansec [index] = None - para resolver todos los identificadores relacionados con el proceso creado (como stdin \ etc.) – N0dGrand87

Cuestiones relacionadas