IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Cast de données - problème mémoire


Sujet :

Python

  1. #1
    Nouveau membre du Club
    Profil pro
    Consultant E-Business
    Inscrit en
    Mai 2007
    Messages
    39
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Consultant E-Business

    Informations forums :
    Inscription : Mai 2007
    Messages : 39
    Points : 29
    Points
    29
    Par défaut Cast de données - problème mémoire
    Bonjour!

    En réalisant les opérations, Python ne semble pas libérer correctement la mémoire allouée:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    ls = [ ['1.0'] * 3000 for i in range(20000)]
     
    ls = [map(float, row) for row in ls]
    ou

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    ls = [ ['1.0'] * 3000 for i in xrange(20000)]
     
    for i in range(len(ls)):
     for j in range(len(ls[i])):
      ls[i][j] = float(ls[i][j])
    Je ne comprends pas pourquoi l'espace mémoire alloué est largement supérieur à celui que possède la liste de liste de float.

    Un del ne règle pas le problème, et gc.collect() n'a pas l'air d'arranger réellement les choses.

    Idem pour la v2 du code avec une variable intermédiaire...

    Quelqu'un a une idée de ce qui se passe vraiment pour que mes 2Go et mon swap aillent jusqu'à se remplir entièrement? (Testé sous Python 2.6.4 et 2.3)

  2. #2
    Nouveau membre du Club
    Profil pro
    Consultant E-Business
    Inscrit en
    Mai 2007
    Messages
    39
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Consultant E-Business

    Informations forums :
    Inscription : Mai 2007
    Messages : 39
    Points : 29
    Points
    29
    Par défaut
    xrange...

  3. #3
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 76
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Points : 1 913
    Points
    1 913
    Par défaut
    Je confirme que sur mon système (python 2.6 sur ubuntu Lucid Lynx)
    l'instruction del est inoéprante
    par contre gc.collect() récupére sinon toute, au moins une bonne partie de la mémoire.
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    import subprocess
    import gc
    class MemoryMonitor(object):
     
        def __init__(self, username):
            """Create new MemoryMonitor instance."""
            self.username = username
     
        def usage(self):
            """Return int containing memory used by user's processes."""
            self.process = subprocess.Popen("ps -u %s -o rss | awk '{sum+=$1} END {print sum}'" % self.username,
                                            shell=True,
                                            stdout=subprocess.PIPE,
                                            )
            self.stdout_list = self.process.communicate()[0].split('\n')
            return int(self.stdout_list[0])
     
    memory_mon = MemoryMonitor('gilles')
    print memory_mon.usage()
    ls = [ ['1.0'] * 3000 for i in range(20000)]
    print memory_mon.usage()
    ls = [map(float, row) for row in ls]
    print memory_mon.usage()
    del ls
    print memory_mon.usage()
    gc.collect()
    print memory_mon.usage()
    """ Résultat de l'exécution:
    672436
    1144088
    3054936
    3053980
    1722168
    """
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  4. #4
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonjour,

    Heuuu... Je vais sans doute dire une bêtise mais cela me semble normal.

    Python réserve un espace mémoire pour les variables suivant le type de variable et non la taille réelle de la variable en mémoire.
    Un del ne fait qu'enlever le binding dans le namespace, pas l'allocation qui dépend du garbage.
    Enfin... C'est ce que j'avais compris.

    @+
    Merci d'utiliser le forum pour les questions techniques.

  5. #5
    Membre éprouvé
    Avatar de afranck64
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2009
    Messages : 592
    Points : 1 006
    Points
    1 006
    Par défaut
    Bonsoir,

    je crois qu'en Python la méthode pour libérer l'espace occupé par une variable c'est de lui affecter la valeur None

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    lst = range(1000000)
    lst = None
    @+ et bon code
    Win 10 64 bits / Linux Mint 18, - AMD A6 Quad: Py27 / Py35
    CONTENU D'UNE QUESTION
    Exemples:
    - Configuration (système d'exploitation, version de Python et des bibliothèques utilisées)
    - Code source du morceau de programme où il y a un bogue
    - Ligne de code sur laquelle le bogue apparaît
    - Erreur complète retournée pas l'interpréteur Python
    - Recherche déjà effectuée (FAQ, Tutoriels, ...)
    - Tests déjà effectués

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 273
    Points : 36 757
    Points
    36 757
    Par défaut
    del X ou X = None ne devraient avoir pour seul effet que de diminuer le nombre de références vers l'objet pointé par la variable X.

    Ce qui permettra au prochain passage du garbage collector de libérer les objets dont le nombre de références est null.

    gc.collect() force le passage du GC et la libération de la mémoire.

    - W
    PS: Lorsqu'on alloue/libère une liste de floats distincts, les résultats sont aussi surprenants.
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonsoir,

    Je doute sur le lst = None. Pas le temps de tester mais cela n'est qu'une nouvelle affectation dans le namespace.

    @+

    Edit : Et mince, wiztricks a déjà répondu.
    Merci d'utiliser le forum pour les questions techniques.

  8. #8
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 76
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Points : 1 913
    Points
    1 913
    Par défaut
    Je doute sur le lst = None. Pas le temps de tester mais cela n'est qu'une nouvelle affectation dans le namespace.
    Ne doutez plus, je viens de faire le test, vous avez raison.
    del lst ou bien lst=None n'entraîne pas le déclenchement du garbage collector. Il faut faire suivre d'un appel explicite.
    Ce qui permettra au prochain passage du garbage collector de libérer les objets dont le nombre de références est null.
    Wiztricks a donc raison aussi.
    NB: Ce comportement est tout à fait logique. Le GC est un processus relativement long, d'autant plus que les liaisons sont en nombre important et que les objets pointés sont gros. S'il y avait appel du GC à chaque réaffectation Python serait encore plus lent.
    Les opposants au GC (comme les fans de C, C++) ont pour argument majeur que le déclenchement pouvant intervenir à des instants aléatoires et donc ralentir d'autant le processus en cours, un tel langage est impropre à la programmation de processus 'temps réel', ce qui est la vérité.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  9. #9
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    La question est marquée résolue mais moi je ne comprends toujours pas.

    Ce qui a été dit sur le gc est vrai, mais en quoi cela justifie une allocation de mémoire aussi importante ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ls = [ ['1.0'] * 3000 for i in range(20000)]
    --> le process Python monte à environ 270 MB
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ls = [ [1.0] * 3000 for i in range(20000)]]
    --> même chose, 270 MB
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ls = [ ['1.0'] * 3000 for i in range(20000)]
    ls = [map(float, row) for row in ls]
    --> 1.4 GB, bien plus que la somme des 2 listes, et gc.collect() n'a effectivement aucun effet si on n'efface pas ls avant...

    Le second code, avec les deux boucles for imbriquées, est plus lent mais se comporte légèrement mieux; il n'alloue "que" 1.2 GB...

    Un début d'explication ici: http://effbot.org/pyfaq/why-doesnt-p...rge-object.htm
    Il semble effectivement que Python ait libéré de la mémoire, mais ne l'ai pas rendue à l'OS. Si après l'opération ci-dessus, alors que Python utilise 1.4 GB, j'alloue un nouveau gros objet de 200 MB, l'utilisation mémoire du processus n'augmente plus. Une autre partie de la réponse est sans doute liée à la "free list" évoquée dans le lien ci-dessus, mais je comprends pas encore bien de quoi il s'agit.

  10. #10
    Expert confirmé Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Points : 4 005
    Points
    4 005
    Par défaut
    Bonsoir,

    Encore une relance comme je les aimes. Merci dividee.

    A lire aussi

    Qu'en est il ?
    Merci d'utiliser le forum pour les questions techniques.

  11. #11
    Membre éprouvé
    Avatar de afranck64
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2009
    Messages : 592
    Points : 1 006
    Points
    1 006
    Par défaut
    Bonsoir,

    Je crois que sur le lien évoqué par dividee ils recommandent d'utiliser xrange au lieu de range pour des grandes valeurs. Comme quoi range(n) occupe n fois la taille d'un entier tandis que xrange(n) n'en occupe que 2 fois vu qu'il ne "traite que 2 éléments à un intant donné".

    If I do

    >>> L = range(50*1024*100)
    >>> del L

    Python is still using more than 60 MB. Why isn’t the memory released?

    It’s that you’ve created 5 million integers simultaneously alive, and each int object consumes 12 bytes. “For speed”, Python maintains an internal free list for integer objects. Unfortunately, that free list is both immortal and unbounded in size. floats also use an immortal & unbounded free list.

    /…/ Do you really need a list containing 5 million integers? I never do ;-) Something like

    for i in xrange(50*1024*100): # note the "x" in "xrange"
    whatever

    consumes a trivial amount of memory, because only two integers in the range are simultaneously alive at any point, and the free list makes reusing their space fast.
    Win 10 64 bits / Linux Mint 18, - AMD A6 Quad: Py27 / Py35
    CONTENU D'UNE QUESTION
    Exemples:
    - Configuration (système d'exploitation, version de Python et des bibliothèques utilisées)
    - Code source du morceau de programme où il y a un bogue
    - Ligne de code sur laquelle le bogue apparaît
    - Erreur complète retournée pas l'interpréteur Python
    - Recherche déjà effectuée (FAQ, Tutoriels, ...)
    - Tests déjà effectués

  12. #12
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Le code de Zavonen du message #3 ne marche pas chez moi:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Traceback (most recent call last):
      File "E:\Python\python27 juillet10\essai.py", line 19, in <module>
        print memory_mon.usage()
      File "E:\Python\python27 juillet10\essai.py", line 16, in usage
        return int(self.stdout_list[0])
    ValueError: invalid literal for int() with base 10: ''








    Ce qui a été dit sur le gc est vrai
    Permettez moi de dire que je crois que non.

    J’ai toujours eu l’impression que beaucoup de monde, et pas des moindres, se fourraient le doigt dans l’œil quand ils parlaient du GC de Python.

    Pour ma part, parallèlement à cette impression, j'ai lu des centaines de fois la doc Python sur le sujet et je n’ai jamais réussi à saisir ce qu’elle signifie exactement.





    Ce que j’ai vu partout comme notion de base plus ou moins clairement/subliminalement énoncée (je ne parle pas de la doc Python), c’est ceci:
    le GC de Python se met en route périodiquement pour faire une collecte et éliminer les objets qui ne sont plus référencés.
    Bof.


    C’est ce qu’évoque Zavonen là dedans:
    Les opposants au GC (comme les fans de C, C++) ont pour argument majeur que le déclenchement pouvant intervenir à des instants aléatoires et donc ralentir d'autant le processus en cours, un tel langage est impropre à la programmation de processus 'temps réel', ce qui est la vérité.
    Le problème, c’est que les sbires en question dans cette citation n’ont pour la plupart jamais examiné Python en profondeur et que si ce que je crois personnellement est vrai, ils ne font que proférer là une ânerie.

    Car ils confondent le GC de Python avec celui de Java, qui lui, d’après ce que j’ai compris, mais j’ai peut être mal compris hein... , est effectivement un GC qui se déclenche périodiquement pour détecter les objets qui ne sont plus référencés par un identifiant, et qui ne travaille QUE comme ça par intervalles.








    Tandis que
    je crois, pour ma part, que le GC de Python est bicéphale, et qu'il travaille en continu pour une tête (le comptage des références ET la déallocation immédiate) et de temps à autre pour l’autre tête (qui fait du nettoyage de référence circulaires)
    C’est mon credo, mais c’est un credo vacillant.



    garbage collection

    The process of freeing memory when it is not used anymore. Python performs garbage collection via reference counting and a cyclic garbage collector that is able to detect and break reference cycles.

    http://docs.python.org/glossary.html...age-collection
    Dans cet extrait, il est absolument clair que la garbage collection est assurée de deux façons. On a au moins ça comme certitude.

    Mais ce qui est subtil, c’est qu’il ne dit pas que c’est le GC qui fait cette collection. Il n’emploie le terme de garbage collector que pour la seconde activité. Ce qui fait que partout où je rencontre GC dans la doc, j’ai tendance à penser qu’il s’agit de la deuxième tête.







    Pour la première activité, il me semble évident que le comptage des références pour chaque objet (RC = reference counting) modifie, instantanément après chaque affectation d’identifiant ou destruction d’identifiant par del, le nombre de références attaché à un objet donné. Bien que ça aussi j’aimerais en trouver une affirmation autorisée explicite.

    Par contre, je n’ai jamais trouvé une doc Python officielle, ni même un texte non officiel, dans lesquels il fût clairement et explicitement dit que le lorsque le RC ramène le nombre de références attachées à un objet à la valeur 0 , il y a aussi un déclenchement IMMÉDIAT de déallocation de la mémoire qu’occupait l’objet.

    Et ça j’aimerais le savoir, parce que si c’est bien ainsi, cela voudrait logiquement dire que ce n’est pas l’autre tête du GC qui s’occuperait de détecter les objets à zéro références, et donc que cette deuxième tête ne s’occuperait que de détecter les références circulaires.



    When an object’s reference count becomes zero, the object is deallocated.

    http://docs.python.org/c-api/intro.h...ference-counts
    Mais c’est quand il y a une collecte ou juste après que le comptage de l’objet devient zéro ?









    Mais si la deuxième tête ne détecte que les références circulaires, il y a une autre ambigüité qui persiste:

    pour la deuxième activité, menée par le cyclic garbage collector,
    si le terme "cyclic" signifie que ce sont les références circulaires qui sont visées par ce machin qui est appelé là garbage collector , qu’en est-il de la fréquence évoquée ici ou là, par exemple:



    gc.set_threshold(threshold0[, threshold1[, threshold2]])
    Set the garbage collection thresholds (the collection frequency). Setting threshold0 to zero disables collection.

    The GC classifies objects into three generations depending on how many collection sweeps they have survived. New objects are placed in the youngest generation (generation 0). If an object survives a collection it is moved into the next older generation.


    Il y est question de la fréquence de .... garbage collection. Si GC = deuxième tête, est-ce que collection (au lieu de collector) inclut RC ? Est-ce que RC fonctionne aussi par intervalles et non pas en continu ???

    « The GC classifies objects into three generations » cela pourrait ne concerner que la deuxième tête cette fois.

    Conclusion: il est question de fréquence, mais je ne sais toujours pas avec certitude de quoi.








    Dans certains passages, les choses me semblent claires:

    27.12. gc — Garbage Collector interface

    This module provides an interface to the optional garbage collector. It provides the ability to disable the collector, tune the collection frequency, and set debugging options. It also provides access to unreachable objects that the collector found but cannot free. Since the collector supplements the reference counting already used in Python, you can disable the collector if you are sure your program does not create reference cycles. Automatic collection can be disabled by calling gc.disable().

    http://docs.python.org/library/gc.html#gc.collect


    Mais peu de temps après je ne sais plus qu’en penser.

    - optional garbage collector : s’il est optionnel on peut en déduire que ça ne recouvre pas le RC. Le RC = comptage ne peut pas ne pas exister. Mais le RC=déallocateur ? Est-ce que cette fonction de déallocation ne pourrait pas être désactivée et ainsi, "garbage collector" recouvrir la partie déallocation du RC ?


    - Since the collector supplements the reference counting :
    là ça paraît imparable, ce qui est appelé collector ne compte pas le RC. Ailleurs ce n’est pas aussi évident. Et ça ne dit toujours pas si le RC est désallocateur immédiat aussi.





    Enfin bref, grosse mélasse pour moi concernant le GC Python.
    Je perçois une ambigüité dans tous les passages des docs et cela ne m’étonne pas que beaucoup de monde me semble être dans un gros malentendu sur le GC, et je me permets de dire que je ne suis pas aussi confiant que vous sur ce qu’il faut comprendre de son fonctionnement.

    Mais c’est peut êre moi qui ne comprend rien.
    Quel est votre avis sur le GC ?

  13. #13
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 273
    Points : 36 757
    Points
    36 757
    Par défaut
    Salut Eyquem
    Dans ce genre de situation, il faut se rappeler que la vérité est dans le code, pas nécessairement dans une documentation qui se limite a décrire plutot que de spécifier.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  14. #14
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 76
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Points : 1 913
    Points
    1 913
    Par défaut
    Bonjour Eyquem,
    Les langages ne sont que des programmes comme les autres.
    Ils ne sont pas exempts de bugs.
    La gestion de la mémoire par python est loin d'être parfaite.
    Voici une référence qui peut t'intéresser:
    http://evanjones.ca/python-memory.html
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Enorme base de données, problème de mémoire
    Par kenzoshin dans le forum Hibernate
    Réponses: 5
    Dernier message: 07/12/2012, 16h12
  2. [JDBC Driver][JSTL] Problème de cast de données
    Par GyLes dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 27/09/2005, 10h00
  3. - [CAST ou CONVERT] Problème de conversion de date
    Par Boublou dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 06/07/2004, 14h31
  4. Problémes mémoire avec le bde sur des bases paradox
    Par Keke des Iles dans le forum Bases de données
    Réponses: 2
    Dernier message: 27/05/2004, 16h55
  5. Problème mémoire avec une dll par chargement dynamique
    Par widze19 dans le forum C++Builder
    Réponses: 6
    Dernier message: 15/12/2003, 13h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo