memory error

memory error - Python - Programmation

Marsh Posté le 21-11-2008 à 15:37:00    

Bonjour,
 
je dois parser une quinzaine de fichiers (dans un format propriétaire) avec python. ça représente au total 150Mo de données à parser. J'ai écrit le parser qui marche très bien et je parse les fichiers un à un dans une boucle, sauf que ... systématiquement ça plante lors de la septième itération avec un "memory error". A la fin de chaque itération, une fois le fichier parsé, les données sont retranscrites dans un fichier texte et le fichier fermé. Quand je relance sur les fichiers restant, ça tourne sans problème.  
Quelqu'un aurait-il une idée de la raison de cette erreur de mémoire ? C'est assez pénible de devoir faire tourner le programme en 2 fois ...  
Je ne manie python que depuis une petite dizaine de jours, help me !

Reply

Marsh Posté le 21-11-2008 à 15:37:00   

Reply

Marsh Posté le 21-11-2008 à 15:41:29    

Je check ma boule de cristal et je te dis ça tout de suite
http://img263.imageshack.us/img263/1195/img2439a0fp.jpg

 

Mais en attendant, si on pouvait avoir des bouts de code pour savoir comment tu ouvres, fermes, et utilises tes fichiers ça pourrait sûrement aider au diagnostic [:dawa]

 

Regarder la consommation mémoire du processus python te serait également, j'en suis certain, bien utile [:dawa]

Message cité 1 fois
Message édité par masklinn le 21-11-2008 à 15:43:14

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 21-11-2008 à 15:53:37    

masklinn a écrit :

Je check ma boule de cristal et je te dis ça tout de suite
http://img263.imageshack.us/img263 [...] 39a0fp.jpg
 
Mais en attendant, si on pouvait avoir des bouts de code pour savoir comment tu ouvres, fermes, et utilises tes fichiers ça pourrait sûrement aider au diagnostic [:dawa]
 [:dawa]


 
La boucle en question :  
 
for fichier in ebm_files[:]:
    MYDATA = EBM_file(fichier)
    Voie = Record(MYDATA)
    Voie.sauvegarde_fichier(repertoire+patient[indice_patient])
    del(MYDATA)
    del(Voie)
 
et la fonction de sauvegarde :  
 
def sauvegarde_fichier(self,repertoire):
        os.chdir(repertoire)
        f = open(self.capteur+'.txt','wb')
        for val in self.valeurs:
            f.write("%3.3e\n" % (val))
        f.close()

Reply

Marsh Posté le 21-11-2008 à 16:02:26    

gaston__lagaffe a écrit :

 

La boucle en question :

Code :
  1. for fichier in ebm_files[:]:
  2.    MYDATA = EBM_file(fichier)
  3.    Voie = Record(MYDATA)
  4.    Voie.sauvegarde_fichier(repertoire+patient[indice_patient])
  5.    del(MYDATA)
  6.    del(Voie)



  • C'est moi ou le fichier EBM n'est jamais fermé?
  • Quel est l'intérêt de dupliquer la liste ebm_files exactement? Pourquoi ne pas itérer directement dessus?
  • Pourquoi ne pas utiliser des fonctions standard?
  • del est un statement, pas de parenthèses et accessoirement ça ne sert pas à grand chose


PS: Naming inconsistant :/ avec du français :/ et ne respecte pas la PEP8

 

Pour la sauvegarde, pourquoi utiliser os.chdir plutôt qu'on os.path.join pour créer un nom complet répertoire compris? Et tu utilises quelle version de Python?

Message cité 1 fois
Message édité par masklinn le 21-11-2008 à 16:04:53

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 21-11-2008 à 16:28:28    

masklinn a écrit :


  • C'est moi ou le fichier EBM n'est jamais fermé?



Les fichiers EBM contiennent des données médicales acquises par différents capteurs : rythme cardiaque, activité cérébrale, saturation du sang en O2, etc ... La classe EBM_file parse le fichier EBM pour en extraire les informations enregistrées (qui ne sont pas celles acquises). La fonction __init__ ouvre et ferme le fichier EBM et stocke les champs. Il faut ensuite les traiter pour retrouver les valeurs enregistrées : c'est ce que je fais avec ma classe Record.
 

masklinn a écrit :


  • Quel est l'intérêt de dupliquer la liste ebm_files exactement? Pourquoi ne pas itérer directement dessus?



pas compris ... Je ne duplique pas la liste ebm_files, enfin je ne crois pas ...
 

masklinn a écrit :


  • Pourquoi ne pas utiliser des fonctions standard?



Quelles sont les fonctions non standard que j'utilise (mises à part les objets EBM_file et Record spécifiques au format EBM pour lesquelles à mon avis il n'existe aucune classe pré-écrite) ? Quelles fonctions standard devrais-je utiliser ?
 

masklinn a écrit :


  • del est un statement, pas de parenthèses et accessoirement ça ne sert pas à grand chose



C'est bien ce que j'avais cru comprendre, mais bon je ne savais pas quoi tenter face à ce memory error, alors bon ...
 
 

masklinn a écrit :


PS: Naming inconsistant :/ avec du français :/ et ne respecte pas la PEP8


C'est quoi la PEP8 ?
 

masklinn a écrit :


Pour la sauvegarde, pourquoi utiliser os.chdir plutôt qu'on os.path.join pour créer un nom complet répertoire compris? Et tu utilises quelle version de Python?


parce que je me suis pris la tête avec os.path.join et que ça génère des erreurs à cause de l'encodage des  alors qu'avec un os.chdir ça marche. J'ai pas d'autre explication ^^

Reply

Marsh Posté le 21-11-2008 à 16:33:47    

gaston__lagaffe a écrit :


Les fichiers EBM contiennent des données médicales acquises par différents capteurs : rythme cardiaque, activité cérébrale, saturation du sang en O2, etc ... La classe EBM_file parse le fichier EBM pour en extraire les informations enregistrées (qui ne sont pas celles acquises). La fonction __init__ ouvre et ferme le fichier EBM et stocke les champs. Il faut ensuite les traiter pour retrouver les valeurs enregistrées : c'est ce que je fais avec ma classe Record.


ok.

gaston__lagaffe a écrit :

pas compris ... Je ne duplique pas la liste ebm_files, enfin je ne crois pas ...


Si, ebm_files[:] ça slice toute la liste => ça en crée une copie

gaston__lagaffe a écrit :

Quelles sont les fonctions non standard que j'utilise (mises à part les objets EBM_file et Record spécifiques au format EBM pour lesquelles à mon avis il n'existe aucune classe pré-écrite) ? Quelles fonctions standard devrais-je utiliser ?


C'était juste ça :jap:

gaston__lagaffe a écrit :

C'est bien ce que j'avais cru comprendre, mais bon je ne savais pas quoi tenter face à ce memory error, alors bon ...


Ben t'as apparement un memleak donc faut voir ce qui leak et où.

gaston__lagaffe a écrit :

C'est quoi la PEP8 ?


Python Style Guide.

gaston__lagaffe a écrit :

parce que je me suis pris la tête avec os.path.join et que ça génère des erreurs à cause de l'encodage des  alors qu'avec un os.chdir ça marche. J'ai pas d'autre explication ^^


mouais :/

 

essaie de t'inspirer de trucs genre http://mail.python.org/pipermail/p [...] 93782.html, http://utcc.utoronto.ca/~cks/space [...] emoryLeaks ou http://mg.pov.lt/blog/hunting-python-memleaks pour tenter de trouver où tu leak de la mémoire.


Message édité par masklinn le 21-11-2008 à 16:38:50

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 29-11-2008 à 18:41:48    

Y a des chances que le problème soit dans ta classe Record, non ?


---------------
Ce n'est point ma façon de penser qui a fait mon malheur, c'est celle des autres.
Reply

Marsh Posté le 29-11-2008 à 21:25:54    

e_esprit a écrit :

Y a des chances que le problème soit dans ta classe Record, non ?


 
c'est possible ... mais pas forcément ! Ca plante de façon aléatoire après plusieurs itérations à un endroit différent à chaque fois. La classe Embla est assez simple, on lit plusieurs octets, on calcule un ID et une valeur et en fonction de l'ID calculé, on associe la valeur calculée à tel ou tel attribut (façon switch)
par contre, la classe record est plus complexe : on effectue une succession d'opérations sur les valeurs enregistrées pour retrouver les valeurs mesuréees.
 
En tout cas, quand je fais tourner en 2 fois le programmes (les 7 premiers fichiers puis les 8 derniers), ça tourne sans planter et ça fonctionne bien... :??:

Reply

Marsh Posté le 29-11-2008 à 21:30:00    

T'as redéfini les méthodes __del__ sur tes objets ?
Si oui peut-être de façon incomplète ?


---------------
Ce n'est point ma façon de penser qui a fait mon malheur, c'est celle des autres.
Reply

Marsh Posté le 29-11-2008 à 22:00:38    

e_esprit a écrit :

T'as redéfini les méthodes __del__ sur tes objets ?
Si oui peut-être de façon incomplète ?


 
euh non, pas redéfini ... Naïvement j'imaginais que ça supprimait toute l'instance, mais c'est peut être pas le cas ... Vais essayer ça ! Merci !

Reply

Marsh Posté le 29-11-2008 à 22:00:38   

Reply

Marsh Posté le 30-11-2008 à 00:23:58    

e_esprit a écrit :

T'as redéfini les méthodes __del__ sur tes objets ?
Si oui peut-être de façon incomplète ?


quel intérêt de faire des del, surtout pour un débutant ???

Reply

Marsh Posté le 30-11-2008 à 00:54:52    

Taz a écrit :


quel intérêt de faire des del, surtout pour un débutant ???


 
quelle autre solution proposes-tu pour mon problème ?

Reply

Marsh Posté le 30-11-2008 à 01:49:47    

gaston__lagaffe a écrit :

 

quelle autre solution proposes-tu pour mon problème ?


montrer ton code ou aller voir une cartomancienne.

 

surtout que bon, même dans des applis en python de plusieurs millions de sloc, tu ne te sers grosso-merdo de del que pour effacer des clefs dans un dict.
T'as genre une boucle infinie qui claque d'abord sur de la mémoire qu'autre chose. 'tain, si tu commencez par donner et regarder ta stacktrace, tu saurais immédiatement d'où ça vient ...

 

(et biensur la gestion de la mémoire est automatique en python, c'est pas la peine de faire des del pour le plaisir)

Message cité 1 fois
Message édité par Taz le 30-11-2008 à 01:54:01
Reply

Marsh Posté le 30-11-2008 à 02:29:06    

Taz a écrit :


montrer ton code ou aller voir une cartomancienne.
 
surtout que bon, même dans des applis en python de plusieurs millions de sloc, tu ne te sers grosso-merdo de del que pour effacer des clefs dans un dict.
T'as genre une boucle infinie qui claque d'abord sur de la mémoire qu'autre chose. 'tain, si tu commencez par donner et regarder ta stacktrace, tu saurais immédiatement d'où ça vient ...
 
(et biensur la gestion de la mémoire est automatique en python, c'est pas la peine de faire des del pour le plaisir)


 
J'ai un problème pour montrer mon code : ça s'inscrit dans un projet de recherche scientifique et je suis tenu par le secret professionnel pour préserver la propriété intellectuelle. J'ai tout à fait conscience que ça rend beaucoup plus difficile de me répondre, mais bon, je fais quoi ?  
Concernant la stacktrace, j'ai juste un MemoryError qui tombe de façon aléatoire après quelques itérations. J'ai essayé de changer l'ordre des fichiers, ça ne change rien; ça plante toujours, jamais au même endroit, jamais pendant le même fichier. Un coup lorsque j'ajoute un entier ou un float à une liste, un coup lorsque j'applique un masque binaire sur un autre vecteur binaire, etc ... A priori rien de super lourd en mémoire. Je l'ai essayé sur des pcs différents, ça plante à chaque fois, y compris sur des pcs haute performance.  
Comme la gestion de la mémoire sous python a l'air un peu bizarre et que j'y connais pas grand chose, j'ai essayé de poser la question pour voir si qqn aurait une idée. Si personne n'a d'idée, c'est pas grave je m'arrangerai pour le faire en 2 fois. Ou alors je passerai sur un autre langage. C'est clair que la quantité de données à traiter est assez lourde; le résultat que je cherche prend tout de même 1,15Go (en moyenne) ...

Reply

Marsh Posté le 30-11-2008 à 10:30:00    

Elle est pas bizarre du tout la gestion de la mémoire.
 
C'est navrant ton attitude de fuite en avant et ton refus de nous montrer ton code: tu crois vraiment que ton code de débutant intéresse les chinois du FBI ? Changer de langage pour un autre que tu ne connais pas non plus ne changera rien si ton code et ton algo sont mauvais. Si t'as 2G de données et que tu t'amuses à les charger 2x, bah ton windows 32bits il va pas aimer.

Reply

Marsh Posté le 30-11-2008 à 13:26:31    

Taz a écrit :

Elle est pas bizarre du tout la gestion de la mémoire.
 
C'est navrant ton attitude de fuite en avant et ton refus de nous montrer ton code: tu crois vraiment que ton code de débutant intéresse les chinois du FBI ? Changer de langage pour un autre que tu ne connais pas non plus ne changera rien si ton code et ton algo sont mauvais. Si t'as 2G de données et que tu t'amuses à les charger 2x, bah ton windows 32bits il va pas aimer.


 
je crois que tu n'as pas bien compris : je suis tenu par le secret professionnel. Ca n'a rien à voir avec les chinois ou le FBI, mais avec le respect de la propriété intellectuelle dans le cadre de la recherche scientifique médicale. Crois tu vraiment que les ingénieurs de microsoft ont le droit de venir déposer leur code sur des forums ? Personnellement, je surfe en permanence entre le secret médical et la propriété intellectuelle; j'ai pas trop le choix en bossant dans la recherche médicale ... Et je ne parle même pas ici du format propriétaire des fichiers que je cherche à parser ... Le parser qu'ils vendent coute 1000 euros; j'imagine même pas la tête qu'ils feront si je mets un code en ligne totalement libre d'accès.
En l'occurrence, j'ai aussi une formation d'ingénieur en informatique donc pas débutant complet dans la programmation. J'ai pas mal travaillé en traitement du signal sous matlab et surtout scilab, donc le même parser existe sous scilab et tourne sans problème, mais en 2 heures ... Nous aurions besoin de maintenant travailler avec de l'objet, et j'ai eu envie de m'intéresser à python, voilà tout!
Et je continue de penser que la gestion de la mémoire est bizarre : il gère la mémoire tout seul, résultat quand je dois parser 15 fichiers d'affilée en utilisant une boucle for, il plante, alors que si je le fais à la main, il ne plante pas; ça a l'air assez mal foutu quand même.  
Concernant les données que j'ai à traiter, je le répète, j'ai au départ 15 fichiers qui occupent au total environ 150 Mo, il s'agit de les parser en effectuant quelques traitements dessus. Ces traitements se font en 2 étapes. La première étape consiste juste à de la lecture d'octets utilisés pour le calcul d'un ID et d'une valeur, ensuite, à la manière d'un switch on affecte la valeur à tel ou tel attribut en fonction de la valeur de l'ID. Dans la deuxième étape, on réutilise l'ensemble des champs remplis dans la première étape (des masques, des gains, des fonctions de calibration, des booléens, des vecteurs, etc ...) de manière à calculer les valeurs physiologiques enregistrées lors de l'examen médical. En l'occurrence, ça plante aléatoirement dans des fichiers différents, aussi  bien dans la première que dans la deuxième étape, à n'importe quelle ligne de code. Au final, je sauvegarde les data dans des fichiers txt par coté pratique et ces 15 fichiers txt prennent 1,15Go de mémoire. Si je retire cette étape de sauvegarde, ça plante quand même. Ce n'est donc pas elle qui fait planter.  
Le problème ne peut pas venir des données à charger car quand je le fais fichier par fichier à la main, ça marche sans problème, la machine est donc tout à fait capable de le faire. Par contre, c'est bien au niveau des itérations que ça plante. il y a forcément des choses qu'il n'efface pas des itérations précédentes et qui occupent de la mémoire pour rien, mais je n'arrive pas à comprendre quoi !

Message cité 1 fois
Message édité par gaston__lagaffe le 30-11-2008 à 13:27:07
Reply

Marsh Posté le 30-11-2008 à 13:30:22    

gaston__lagaffe a écrit :

il y a forcément des choses qu'il n'efface pas des itérations précédentes et qui occupent de la mémoire pour rien, mais je n'arrive pas à comprendre quoi !


Et je t'ai fourni des liens sur la recherche de memory leaks en python...

 

Python a une gestion de la mémoire très simple par refcount, si tu as un memleak c'est 90% du temps parce que tu conserves des références sur des données dont tu n'as plus besoin, c'est donc un problème dans ton implémentation.

 

Il n'y a toujours pas de magiciens dans le coin, donc on peut pas t'aider plus que ça.

Message cité 1 fois
Message édité par masklinn le 30-11-2008 à 13:31:49

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 30-11-2008 à 13:32:17    

Dans ce cas, tu peux forcer l'appel au GC en utilisant del.


---------------
Nos estans firs di nosse pitite patreye...
Reply

Marsh Posté le 30-11-2008 à 13:34:46    

KangOl a écrit :

Dans ce cas, tu peux forcer l'appel au GC en utilisant del.


Cf le code au dessus, il en a déjà mis, mais si tu sais pas où est le leak tu vas pas appeler del (ou faire un = None) sur les bons éléments, et le problème ne change pas [:spamafote]

 

C'est pas possible de résoudre des problèmes de perfs sans profiler pour savoir d'où viennent ces problèmes, et un memleak c'est un problème de perfs.


Message édité par masklinn le 30-11-2008 à 13:34:51

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 30-11-2008 à 14:16:37    

masklinn a écrit :


Et je t'ai fourni des liens sur la recherche de memory leaks en python...
 
Python a une gestion de la mémoire très simple par refcount, si tu as un memleak c'est 90% du temps parce que tu conserves des références sur des données dont tu n'as plus besoin, c'est donc un problème dans ton implémentation.
 
Il n'y a toujours pas de magiciens dans le coin, donc on peut pas t'aider plus que ça.


 
Oui mais justement, pour le moment je n'ai pas encore réussi à voir ce qui n'allait pas. Le nombre de références n'augmente pas. J'ai pas encore tout testé c'est vrai.
 
Si personne n'a d'idée, c'est pas grave, je voulais poser la question, je me doute que c'est pas facile d'y répondre, si c'est impossible, tant pis

Reply

Marsh Posté le 30-11-2008 à 15:38:22    

Taz a écrit :


quel intérêt de faire des del, surtout pour un débutant ???


Je lui ai pas conseillé de le faire, je lui ai demandé si il l'avait fait, ce qui aurait pu être la cause de son problème.


---------------
Ce n'est point ma façon de penser qui a fait mon malheur, c'est celle des autres.
Reply

Marsh Posté le 30-11-2008 à 15:42:11    

gaston__lagaffe a écrit :


 
Oui mais justement, pour le moment je n'ai pas encore réussi à voir ce qui n'allait pas. Le nombre de références n'augmente pas. J'ai pas encore tout testé c'est vrai.
 
Si personne n'a d'idée, c'est pas grave, je voulais poser la question, je me doute que c'est pas facile d'y répondre, si c'est impossible, tant pis


 
Mais c'est pas du tout impossible  :pfff:  
Je suis sur que Python propose des lib qui te permettent de profiler ton application, pour voir où passe la mémoire..


---------------
Si la vérité est découverte par quelqu'un d'autre,elle perd toujours un peu d'attrait
Reply

Marsh Posté le 30-11-2008 à 16:01:18    

esox_ch a écrit :


 
Mais c'est pas du tout impossible  :pfff:  
Je suis sur que Python propose des lib qui te permettent de profiler ton application, pour voir où passe la mémoire..


 
oui c'est un peu ce que je cherche. L'idéal serait de pouvoir faire un état de la mémoire. Dans l'absolu c'est pas gravissime, le programme marche, il faut juste le faire tourner 2 fois ...

Reply

Marsh Posté le 30-11-2008 à 16:33:50    

bon touchage de nouilles sur tes 30 lignes de python appartenant à la NASA.

Reply

Marsh Posté le 30-11-2008 à 19:08:30    

gaston__lagaffe a écrit :


 
oui c'est un peu ce que je cherche. L'idéal serait de pouvoir faire un état de la mémoire. Dans l'absolu c'est pas gravissime, le programme marche, il faut juste le faire tourner 2 fois ...


 
Alors tape "profiler python" dans google et tu vas trouver ce que tu cherches.  :sarcastic:


---------------
Si la vérité est découverte par quelqu'un d'autre,elle perd toujours un peu d'attrait
Reply

Marsh Posté le 30-11-2008 à 19:43:49    

esox_ch a écrit :


 
Alors tape "profiler python" dans google et tu vas trouver ce que tu cherches.  :sarcastic:


Ca va le mener à cProfiler et hotshot qui sont des CPU/call profilers, j'ai donné 2 ou 3 liens indiquant la procédure de base et surtout le module à utiliser (gc) sauf à la limite si il est sous Solaris, je ne sais pas ce que le python instrumenté donne, DTrace fournit potentiellement plus d'infos.


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 30-11-2008 à 19:50:25    

Bon je n'ai pas non plus dit que c'était le premier lien..
Et bien là je crois qu'il a vraiment tout ce qu'il lui faut pour résoudre son problème.. Maintenant s'il préfère livrer un programme qu'il faut faire marcher 2 fois ...


---------------
Si la vérité est découverte par quelqu'un d'autre,elle perd toujours un peu d'attrait
Reply

Marsh Posté le 30-11-2008 à 21:59:43    

esox_ch a écrit :

Bon je n'ai pas non plus dit que c'était le premier lien..
Et bien là je crois qu'il a vraiment tout ce qu'il lui faut pour résoudre son problème.. Maintenant s'il préfère livrer un programme qu'il faut faire marcher 2 fois ...


 
Je n'ai rien à livrer, c'est un projet de recherche, je n'ai donc pas de cahier des charges et à l'heure actuelle, il n'y a rien comme concurrence. Je travaille dans un contexte où toute amélioration est la bienvenue. Et puis, j'ai fait un parser sous scilab qui permet de tout parser en une seule fois, il est juste très long...  
Je regarderai ça quand je pourrai, merci à tout le monde pour les conseils.

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed