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

C++ Discussion :

Gestion de la mémoire [Débutant(e)]


Sujet :

C++

  1. #1
    Invité
    Invité(e)
    Par défaut Gestion de la mémoire
    Bonjour à tous,

    Je suis débutant en C++ et j'aurais une question extrêment vague : quelles sont les erreurs fréquentes de codage qui engendrent de grandes fuites de mémoire ?

    Je m'explique : je suis en train de créer un petit lecteur audio en C++ / SDL (je n'en suis qu'au début).

    Quand j'ouvre la boîte de dialogue "Ouvrir", et que je regarde ce que ça consomme en faisant Ctrl Alt Suppr, je vois qu'à chaque fois que je redessine la boîte de dialogue, l'application utilise 20 Mo de plus... alors que la mémoire utilisée devrait logiquement être constante.

    Je suppose que c'est cela qu'on appelle les "fuites de mémoire", et je crois aussi savoir que c'est dû principalement aux allocations dynamiques. Et pourtant, j'ai relu tout mon code plusieurs fois : à chaque "malloc" correspond un "free", et à chaque "new" correspond un "delete". Y compris dans les constructeurs et dans les destructeurs...

    Donc ma question est : est-ce qu'il y a des cas où il y a des subtilités, est-ce qu'il peut y avoir des fuites de mémoire même quand à chaque "new" correspond un "delete", ou bien est-ce qu'il s'agit forcément d'une libération qui n'a pas lieu ?


    Désolé d'être aussi vague, mais je suis vraiment perdu


    Je vous remercie

  2. #2
    Membre expérimenté Avatar de Kujara
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    262
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 262
    Par défaut
    Hmm, si ce n'est pas les couples new / delete, c'est probablement la mémoire allouée / desalloué par les fonctions SDL que tu utilise.

    Je ne connais pas SDL, mais fait attention : si il y a des fonctions create, pense a bien utiliser la fonction delete/destroy correspondante pour demander a SDL de detruire l'objet que tu lui a demandé de creer precedemment...

  3. #3
    Membre éclairé

    Profil pro
    Étudiant
    Inscrit en
    Juin 2006
    Messages
    78
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2006
    Messages : 78
    Par défaut
    La principale cause des fuites mémoire en C++ est de ne pas utiliser le RAII : http://arb.developpez.com/c++/raii/shared_ptr/.

    Ton probleme me fait penser à une allocation de ressource dans une boucle, voir même dans la boucle principale.
    Est-tu sûr de n'ouvrir les images dont tu as besoin pour ton interface qu'une seul fois ?
    C'est clair que si tu ouvre la même image pour la mettre en mémoire à chaque itération, il n'est pas étonant que tu monte de 20Mo par seconde !

    Une fuite mémoire est dû à une allocation dynamique, mais cette allocation peut très bien être cachée dans une fonction (d'ouverture d'image pour SDL, par exemple), attention donc à toujours utiliser les fonctions associées pour liberer les ressources.

    Et oui, il peut y avoir des probleme même quand un delete est appelé : lorsqu'un new[] a creer l'instance.

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Personnellement, je considère que shared_ptr ce n'est pas du vrai RAII, puisqu'il y a partage.

    Le RAII, c'est simplement faire l'acquisition de toutes les ressources dans le constructeur et les libérer dans le destructeur. Si tu copies l'objet il faut donc copier les ressources etc. (si tu choisis de rendre l'objet copiable)
    A priori donc, le RAII c'est justement la propriété unique et sans partage.

  5. #5
    Membre éclairé

    Profil pro
    Étudiant
    Inscrit en
    Juin 2006
    Messages
    78
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2006
    Messages : 78
    Par défaut
    Citation Envoyé par loufoque Voir le message
    Personnellement, je considère que shared_ptr ce n'est pas du vrai RAII, puisqu'il y a partage.

    Le RAII, c'est simplement faire l'acquisition de toutes les ressources dans le constructeur et les libérer dans le destructeur. Si tu copies l'objet il faut donc copier les ressources etc. (si tu choisis de rendre l'objet copiable)
    A priori donc, le RAII c'est justement la propriété unique et sans partage.
    Je pense la même chose, mais j'ai utilisé le moteur de recherche du site et je suis tombé là dessus. Je l'ai mit plus comme un exemple que comme definition du RAII ; merci de la précision !

    Pour une definition plus formelle du RAII : http://en.wikipedia.org/wiki/Resourc...Initialization.

  6. #6
    Membre éclairé
    Avatar de Le Barde
    Homme Profil pro
    Chanteur
    Inscrit en
    Juillet 2007
    Messages
    343
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Chanteur

    Informations forums :
    Inscription : Juillet 2007
    Messages : 343
    Par défaut
    Hello,
    à un niveau moindre (je suis également débutant), il y a aussi le delete[] auquel il faut penser pour libérer les tableaux.

  7. #7
    Invité
    Invité(e)
    Par défaut
    Merci à vous quatre pour vos réponses aussi rapides que claires !

    Citation Envoyé par Kujara Voir le message
    Hmm, si ce n'est pas les couples new / delete, c'est probablement la mémoire allouée / desalloué par les fonctions SDL que tu utilise.

    Je ne connais pas SDL, mais fait attention : si il y a des fonctions create, pense a bien utiliser la fonction delete/destroy correspondante pour demander a SDL de detruire l'objet que tu lui a demandé de creer precedemment...
    Oui, justement j'ai également relu le code pour vérifier que chaque "surface" allouée était détruite par un "SDL_FreeSurface()". Je suis pratiquement certain de n'avoir rien oublié.

    Citation Envoyé par Aszarsha Voir le message
    La principale cause des fuites mémoire en C++ est de ne pas utiliser le RAII : http://arb.developpez.com/c++/raii/shared_ptr/.

    Ton probleme me fait penser à une allocation de ressource dans une boucle, voir même dans la boucle principale.
    Est-tu sûr de n'ouvrir les images dont tu as besoin pour ton interface qu'une seul fois ?
    C'est clair que si tu ouvre la même image pour la mettre en mémoire à chaque itération, il n'est pas étonant que tu monte de 20Mo par seconde !

    Une fuite mémoire est dû à une allocation dynamique, mais cette allocation peut très bien être cachée dans une fonction (d'ouverture d'image pour SDL, par exemple), attention donc à toujours utiliser les fonctions associées pour liberer les ressources.
    Oui, je vais sans doute m'orienter vers les RAII (bien que je ne connaisse pas encore bien les exceptions). Ca a l'air d'être un truc efficace.

    Mais donc logiquement, si je libère toutes mes surfaces, il ne devrait pas y avoir de fuites de mémoire ? Alors je ne vois pas d'où ça peut venir ! Mais ça a peut-être un lien avec la structure de mon programme... En fait, il y a toujours un point sur lequel je ne sais pas trop quoi faire : la méthode qui me bouffe les 20 Mo par seconde, qui s'appelle "dessiner()", et qui est membre de l'objet "DialogOpen", est appelée toutes les 50 secondes (si elle doit être appelée bien sûr). Donc, à chaque appel, je dois créer une surface, dessiner dessus, afficher la surface, puis libérer la surface.

    Alors pour éviter de perdre trop de temps, j'ai pensé à créer un attribut "rectangle" qui n'est rien d'autre que la surface, et qui est donc conservée telle quelle tant que mon objet existe. Du coup, si aucune modification ne doit avoir lieu sur ma surface, au lieu de tout redessiner, je ne fais qu'afficher la surface déjà existante. C'est juste pour gagner du temps.

    Mais j'ai peur que le problème puisse venir de là (bien que le destructeur libère cette surface) ; et même si ce n'est pas le cas, je me demandais si c'était une bonne technique. Un petit peu comme les variables globales : ça peut simplifier la vie, mais c'est maladroit...


    Merci encore pour toute l'aide que vous m'avez déjà apportée.

  8. #8
    Membre éclairé

    Profil pro
    Étudiant
    Inscrit en
    Juin 2006
    Messages
    78
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2006
    Messages : 78
    Par défaut
    Sans code, il va nous être bien difficile de plus t'aider.
    Tu sembles avoir isolé le probleme, peut-être peux-tu nous montrer une partie minimale du code ?

  9. #9
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    tu as peut etre fait des truc comme :

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    bool function(...)
    {
    int * tab = new int(100);
    .
    .
    .
    if (test) return false;//tab n'est pas désalloué donc fuite mémoire
    .
    .
    .
     
    delete [] tab;
    return true;
    }

  10. #10
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Aisément résolu en écrivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    bool function(...)
    {
    std::vector<int> tab(100);
    .
    .
    .
    if (test) return false;
    .
    .
    .
     
    return true;
    }

  11. #11
    Membre éclairé

    Profil pro
    Étudiant
    Inscrit en
    Juin 2006
    Messages
    78
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2006
    Messages : 78
    Par défaut
    Citation Envoyé par jo_le_coco Voir le message
    Oui, justement j'ai également relu le code pour vérifier que chaque "surface" allouée était détruite par un "SDL_FreeSurface()". Je suis pratiquement certain de n'avoir rien oublié.
    C'est typiquement le genre de situation qui rend le C++ un langage au dessus des autres lorsqu'il est bien utilisé. Et ici, il faut encore une fois citer l'idiome RAII.

    Tu devrait encapsuler toute les fonctions d'allocation/ouverture de la SDL dans des class utilisant le RAII, en recuperant la ressource dans le constructeur, et en la rendant dans le destructeur.

    Il y a un nombre incroyable d'erreur de ce type qu'il est possible de réaliser en C ou en Java (et bien d'autres) qui ne sont en C++ qu'une preuve que le developpeur ne sais pas programmer dans ce langage ; ne sais au moins pas l'utiliser efficacement.

    D'ailleurs, le code de Mongaulois repris par loufoque montre bien l'avantage du RAII.

  12. #12
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Ou même exemple avec la sdl :

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    bool function(...)
    {
     
    SDL_NewSurface(surface)//je ne connait pas la SDL
    .
    .
    .
    if (test) return false;//surface n'est pas désalloué donc fuite mémoire
    .
    .
    .
     
    SDL_FreeSurface(surface)
    return true;
    }

  13. #13
    doccpu
    Invité(e)
    Par défaut
    Je sait par expérience que windows lorsce qu'il travaille avec la sdl met en cache du code en mémoire le tout est de s'assurer qu'il la libère à la fermeture en regardant l'espace mémoire libre après fermeture.

    Il se peux aussi que tu encapsule du code sdl dans un objet c++ que tu ne libère pas a cause d'une boucle ou d'une condition

    typiquement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    while (qqchose)
    {
    //création
    MonObjetCppSurSDL * mocssdl = new MonObjetCppSurSDL();
     
    if (qqchosedautre) 
    {
    //...
    exit;
    //la destruction n'est pas effectuée a ce moment là
    }
    // destruction
    delete(mocssdl);
    }

  14. #14
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par doccpu Voir le message
    Je sait par expérience que windows lorsce qu'il travaille avec la sdl met en cache du code en mémoire le tout est de s'assurer qu'il la libère à la fermeture en regardant l'espace mémoire libre après fermeture.
    ? que veut tu dire?

  15. #15
    doccpu
    Invité(e)
    Par défaut
    Citation Envoyé par Mongaulois Voir le message
    ? que veut tu dire?
    parfois il met du code en cache dans la mémoire en cherchant a la réutiliser (sans la détruire immédiatement) mais si ton appli ne libère pas la mémoire a la fermeture c'est que c'est une vraie fuite de mémoire

  16. #16
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Citation Envoyé par doccpu Voir le message
    parfois il met du code en cache dans la mémoire en cherchant a la réutiliser (sans la détruire immédiatement) mais si ton appli ne libère pas la mémoire a la fermeture c'est que c'est une vraie fuite de mémoire
    dsl j'avais mal lu t'as phrase.
    Par contre :
    - "parfois il met du code en cache dans la mémoire", il me semble que c'est beaucoup plus que parfois, presque toujours même, non?

    - "si ton appli ne libère pas la mémoire a la fermeture c'est que c'est une vraie fuite de mémoire", il me semble plutôt que la mémoire utilisé par une appli est libéré quand elle est fermé (désalloué ou non). Une fuite mémoire c'est pendant l'exécution, quand t'as mémoire utilisé augmente au cours du temps a cause de désallocation oubliée.

  17. #17
    Invité
    Invité(e)
    Par défaut
    Merci pour toutes ces réponses.

    Citation Envoyé par Aszarsha Voir le message
    Sans code, il va nous être bien difficile de plus t'aider.
    Tu sembles avoir isolé le probleme, peut-être peux-tu nous montrer une partie minimale du code ?
    Ben en fait, je croyais avoir trouvé la fonction qui prenait toute cette mémoire, mais finalement j'ai fait en sorte qu'elle ne soit appelée qu'une fois pour toutes, et rien à faire : les fuites mémoires sont toujours là. Je ne sais plus où chercher... Mais il est certain que c'est un oubli de libération qui se cache quelque part...


    Citation Envoyé par Mongaulois Voir le message
    tu as peut etre fait des truc comme :

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    bool function(...)
    {
    int * tab = new int(100);
    .
    .
    .
    if (test) return false;//tab n'est pas désalloué donc fuite mémoire
    .
    .
    .
     
    delete [] tab;
    return true;
    }
    Citation Envoyé par loufoque Voir le message
    Aisément résolu en écrivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    bool function(...)
    {
    std::vector<int> tab(100);
    .
    .
    .
    if (test) return false;
    .
    .
    .
     
    return true;
    }
    Malheureusement je ne connais pas encore les "vecteurs". Mais de toute façon, je n'ai pas non plus fait ce type d'erreur, à ma connaissance.

    Citation Envoyé par doccpu Voir le message
    Je sait par expérience que windows lorsce qu'il travaille avec la sdl met en cache du code en mémoire le tout est de s'assurer qu'il la libère à la fermeture en regardant l'espace mémoire libre après fermeture.
    Citation Envoyé par doccpu Voir le message
    parfois il met du code en cache dans la mémoire en cherchant a la réutiliser (sans la détruire immédiatement) mais si ton appli ne libère pas la mémoire a la fermeture c'est que c'est une vraie fuite de mémoire
    Oui, maintenant que tu me dis ça, j'ai aussi remarqué que très souvent, je ne fais quasiment rien (un mouvement de souris anodin), et de la mémoire supplémentaire semble allouée sans aucune raison. Mais d'habitude, il s'agit juste de quelques octets ; là, c'est une dizaine de Mo !

    Mais alors comment détecter cela ? Et comment savoir combien de mémoire n'a pas été libérée à la sortie du programme ? (Si ça peut aider, j'utilise Code::Blocks.)


    Bon quoi qu'il en soit, je vais pour la n-ième fois relire le code. Si je ne trouve rien de nouveau, j'essaierai de tout recoder avec les RAII. Je vous tiendrai au courant

  18. #18
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Fait du pas à pas (je croit que tu peut le faire en debug avec gdb et code::blocks), tu trouvera bien la fonction qui t'alloue 20 Mo a chaque fois.

  19. #19
    doccpu
    Invité(e)
    Par défaut
    Citation Envoyé par Mongaulois Voir le message
    - "si ton appli ne libère pas la mémoire a la fermeture c'est que c'est une vraie fuite de mémoire", il me semble plutôt que la mémoire utilisé par une appli est libéré quand elle est fermé (désalloué ou non). Une fuite mémoire c'est pendant l'exécution, quand t'as mémoire utilisé augmente au cours du temps a cause de désallocation oubliée.
    ca c'est sous linux pas sous windows. Sous windows le tas n'est pas récupéré.

  20. #20
    Membre éclairé

    Profil pro
    Étudiant
    Inscrit en
    Juin 2006
    Messages
    78
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2006
    Messages : 78
    Par défaut
    Citation Envoyé par doccpu Voir le message
    ca c'est sous linux pas sous windows. Sous windows le tas n'est pas récupéré.
    Uniquement avec des systèmes qui datent de plus d'une dixaine d'années, ok ; et encore...
    M'enfin tous les systèmes actuels le font sans aucun probleme, et je ne pense pas que jo_le_coco vise Win9x.

    Une fuite mémoire ne se passe que lors de l'execution du programme, à sa terminaison, toute les resources sont automatiquement recupérés par le système (à moins de programmer pour de très vieux systemes, comme dit plus haut).

    Perso, je ne pense pas qu'il s'agisse d'une fonction qui alloue 20Mo à chaque appel, ca me semble vraiment enorme. Je viserais plutôt vers des petites allocations (quelques ko, voir moins) dans une boucle.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 17
    Dernier message: 02/02/2006, 12h03
  2. gestion de la mémoire
    Par moldavi dans le forum C++
    Réponses: 17
    Dernier message: 04/02/2005, 23h18
  3. Réponses: 11
    Dernier message: 26/12/2004, 22h50
  4. Gestion de la mémoire entre plusieurs DLL
    Par Laurent Gomila dans le forum C++
    Réponses: 7
    Dernier message: 27/07/2004, 15h28
  5. Gestion des variables - mémoire ?
    Par RIVOLLET dans le forum Langage
    Réponses: 4
    Dernier message: 26/10/2002, 12h44

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