2009-02-18 11 views
7

Mon programme semble fuir les handles de fichiers. Comment puis-je savoir où?Détecte les fuites de handle de fichier en python?

Mon programme utilise des handles de fichiers à différents endroits - sortie de processus fils, appelez ctypes API (ImageMagick) ouvre les fichiers, et ils sont copiés.

Il se bloque dans shutil.copyfile, mais je suis sûr que ce n'est pas l'endroit où il fuit.

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

Pas tout à fait une réponse, mais si vous utilisez Python 2.5 ou plus récent, regardez dans le mot clé "with" qui peut automatiquement fermer les fichiers pour vous une fois que vous avez terminé avec eux. –

Répondre

3

Regardez sortie de ls -l /proc/$pid/fd/ (en remplaçant le PID de votre processus, bien sûr) pour voir quels fichiers sont ouverts [ou, win32, utilisez Process Explorer à la liste des fichiers ouverts]; alors déterminez où dans votre code vous les ouvrez, et faites que close() est appelé. (Oui, le garbage collector finira par fermer les choses, mais ce n'est pas toujours assez rapide pour éviter de manquer de fds).

La vérification des références circulaires susceptibles d'empêcher la collecte des données est également une bonne pratique. (Le collecteur de cycles finira par s'en débarrasser - mais il risque de ne pas fonctionner assez fréquemment pour éviter l'épuisement des descripteurs de fichiers, ce qui m'a personnellement fait mordre).

+0

Je suppose qu'il s'agit d'une boîte win32, étant donné les chemins c: \ python25. – twk

+0

Garbage collection: Est-ce que python n'a pas quelque chose comme le collecteur de cycles dans certaines implémentations js? –

+0

@Stuart - Il s'agit d'un GC compté par référence avec un collecteur de cycles, mais le collecteur de cycles ne fonctionne pas assez fréquemment pour fermer nécessairement les objets fichiers non référencés avant que la RAM ne soit épuisée. –

3

Utilisez Process Explorer, sélectionnez votre processus, Affichage-> Affichage du volet inférieur-> Poignées - puis recherchez ce qui semble déplacé - généralement beaucoup de fichiers identiques ou similaires ouvrent des points au problème.

3

lsof -p <process_id> fonctionne bien sur plusieurs systèmes de type UNIX, y compris FreeBSD.

+0

Évidemment question est sur Windows. – Olli

3

J'ai eu des problèmes similaires, à court de descripteurs de fichiers lors des appels subprocess.Popen(). J'ai utilisé le script suivant pour déboguer ce qui se passe:

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

Vous pouvez importer ce module et appeler fd_table_status_str() pour enregistrer l'état de la table des descripteurs de fichiers à différents points dans votre code.

De même, assurez-vous que les instances subprocess.Popen sont détruites. Conserver les références des instances Popen dans Windows empêche l'exécution du GC. Et si les instances sont conservées, les tuyaux associés ne sont pas fermés. Plus d'info here.

+0

"De même, assurez-vous que les instances de sous-processus.Popen sont détruites.Si les références des instances Popen dans Windows empêchent l'exécution du GC, et que les instances sont conservées, les canaux associés ne sont pas fermés. le sujet dans mon cas. Nous le résolvons via pOpenInstansec [index] = None - pour résoudre tous les descripteurs liés au processus créé (tel que stdin \ etc.) – N0dGrand87