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 :

Fuites massive de mémoire! Mais pourquoi? :/


Sujet :

C

  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Juin 2006
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Juin 2006
    Messages : 122
    Par défaut Fuites massive de mémoire! Mais pourquoi? :/
    Bonjour les gens!

    Il m'arrive souvent de passer sur le forum à la recherche de solution pour pas mal de problème de programmation. D'habitude je trouve la solution, mais là, je dois avouer que je suis coincé à cause d'une grosse lacune dans mes connaissances du C. =p

    On va attaquer le problème tout de suite : des fuites mémoire... Massive!

    Je développe un petit shoot'em up en C à base de SDL. Je travail à taton. J'identifie les problèmes à la conception du jeu, puis je les résous. Le résultat final me servira à éditer mon propre shoot'em up comme j'ai toujours voulus en voir un comme je les aime. =)

    Jusqu'ici, ça va, j'ai mon écran qui s'affiche avec un ptit vaisseau qui bouge et qui tire plein de boulette!

    Là où ça cloche, c'est lorsque je regarde le gestionnaire de tâche windows : mon processus prend environ 4,4 Mo (Mega Octet) de mémoire supplémentaire par seconde! Autant dire que le petit exécutable qui ne prend que 230ko bouffe à lui seul plusieurs Go de mémoire au bout de 3 4 minutes d'exécution...

    Va me falloir donc faire du ménage mais... Comment?

    Comment identifier une fuite de mémoire dans mon code ?
    Comment la libérer ?
    J'ai déjà aperçus des choses sur les free(), mais j'associe instinctivement cette fonction avec les malloc() / realloc() et rien d'autre. (Et je n'utilise explicitement aucun malloc() ou realloc() dans mon code.)

    Ci joint le code de mon jeu : testshump.zip

    J'ai joint tout les .h et .c du projet, avec un minimum syndicale de commentaire. (J'ai essayé d'utiliser une programmation orientée objet ou ce qui y ressemble avec les structures et des noms relativement clair. C'est pas la perfection, mais ça aide à comprendre.)

    Je ne demande pas un nettoyage de mon code hein. ;p Mais j'aimerais qu'on me mette sur la piste, avec un exemple tiré du code (ce qui ne va pas, pourquoi ça ne va pas, un exemple du bout de code sans les fuites), de manière à ce que je puisse faire mon ménage et surtout trouver une habitude et l'appliquer pour la suite de ce développement.

    Ouai c'est presque vous demander une petite leçon de mémoire et de pointeur. (C'est pas pour rien que je post chez les débutants!) =p

    Si vous avez des questions pour faire avancer le schmilblik, je suis dispo!
    Si vous voulez l'exécutable (mais je doute que ça vous serves), je peux le joindre également. :o

  2. #2
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2006
    Messages
    242
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2006
    Messages : 242
    Par défaut
    Pour détecter les fuites mémoires, moi j'utilise valgrind (en ligne de commande, avec --leak-check=full) . C'est très pratique (et ça permet aussi de détecter les erreurs d'exécution type erreur de segmentation). Cela dit, je sais pas si ça pourrait s'appliquer à ton projet...
    C'est vrai qu'à priori tu n'utilises pas de malloc. Donc, même si je n'y connais rien à la SDL, c'est que ce que tu alloues dynamiquement, c'est là dedans, mais par le biais d'autres fonctions de la SDL, probablement appelées dans la boucle principale de ta fonction main. Il existe surement des autres fonctions SDL pour supprimer ce que tu as créé...

  3. #3
    Membre émérite Avatar de SofEvans
    Homme Profil pro
    Développeur C
    Inscrit en
    Mars 2009
    Messages
    1 084
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C

    Informations forums :
    Inscription : Mars 2009
    Messages : 1 084
    Par défaut
    salut,

    Je suis en train de regarder ton code.

    C'est juste pout te dire, dans main.c :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        char message[20][200] = {"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"", "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,""};
     
        printf("Tableau de message initialisé\n");
    Je ne crois pas que cela initialise tout le tableau.

    Il faut plutot faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
        char message[20][200];
     
        int i,j;
        for (i = 0 ; i < 20 ; i++)
            for (j = 0 ; j < 200 ; j++)
                message[i][j] = "";
     
        printf("Tableau de message initialisé\n");

    Voila, je continue


    EDIT :


    Une autre erreur (qui n'a rien a voir avec la fuite de memoire) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
        while(continuer)
        {
                        t_fps_actuel = SDL_GetTicks();
     
                        /* Gestion des contrôles */
                        SDL_PollEvent(&event);
                        switch(event.type)
    Ceci est erronné. Si tu procede comme ca, a chaque tour dans ta boucle, tu va avoir X evenement mis dans la file d'attente et un seul sera gerer. Apres plusieurs seconde, si beaucoup d'evenement se mettent dans la file d'attente (nottament des SDL_MOUSEMOTION), tu va avoir une desynchronisation du moment ou tu envoie l'evenement et au moment ou celui ci sera effectue.

    Il faut mettre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
        while(continuer)
        {
                        t_fps_actuel = SDL_GetTicks();
     
                        /* Gestion des contrôles */
                        while(SDL_PollEvent(&event))
                        {
                            switch(event.type)
    Le while permettant de bien gerer les X eveneùent empilié et non un seul


    ******
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
                                            case SDLK_s:
                                            case SDLK_DOWN:
                                                if(monVaisseau.direction[BAS] == 0);
                                                    monVaisseau.direction[BAS] = 1;
                                                break;
    Pas de ; a la fin du if (ligne 84 de main.c)

  4. #4
    Membre émérite Avatar de SofEvans
    Homme Profil pro
    Développeur C
    Inscrit en
    Mars 2009
    Messages
    1 084
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C

    Informations forums :
    Inscription : Mars 2009
    Messages : 1 084
    Par défaut
    Il y a un truc bizarre.

    J'ai supprimer le include de Fmod, j'ai commenter la partie debugMode de l'affichage car celle-ci déclenche un SegmentFault, je l'ai corrigé avec mes remarque precedente et tout marche, je n'ai pas de fuite de mémoire. Même en le laissant tourner trois plomb et en tirant comme un fou, il n'y a pas un seul octet de fuite.

    Je te suggère plutôt de regarder ce morceaux de code qui provoque un segmentFault

    Code : 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
     
                                        if(debugMode)
                                        {
                                                     /* Affichage de l'état des variables à l'écran
                                                      sprintf(message[0], "Position : [%ld, %ld]", position.x, position.y);
                                                      sprintf(message[1], "Position vaisseau : [%.2f, %.2f]", monVaisseau.x, monVaisseau.y);
                                                      for(i = 0; i < 3; i++)
                                                            sprintf(message[i+2], "Position de l'arme %ld : [%.2f, %.2f]", i, monVaisseau.arme[i].x, monVaisseau.arme[i].y);
                                                      for(i = 0; i < 10; i++)
                                                            sprintf(message[i+5], "Etat projectile %ld : %ld, [%.2f, %.2f]", i, monVaisseau.arme[0].projectile[i].type, monVaisseau.arme[0].projectile[i].x, monVaisseau.arme[0].projectile[i].y);
                                                      sprintf(message[15], "Direction du vaisseau : [h = %ld, b = %ld, g = %ld, d = %ld]", monVaisseau.direction[HAUT], monVaisseau.direction[BAS], monVaisseau.direction[GAUCHE], monVaisseau.direction[DROITE]);
                                                      sprintf(message[16], "Framerate = %lf", FrameRate);
                                                      sprintf(message[17], "SDL_GetTicks = %ld", SDL_GetTicks());
     
     
                                              for(i = 0; i < 20; i++)
                                              {
                                                            if(message[i] != "")
                                                            {
                                                                          texte[i] = texte[i] = TTF_RenderText_Solid(police, message[i], couleurFont);
                                                                          positionTexte.x = 10;
                                                                          positionTexte.y = TAILLE_FONT * 1.2 * (i+1);
                                                                          SDL_BlitSurface(texte[i], NULL, ecran, &positionTexte);
                                                            }
                                              }
                                        }
    Voila, j'espere que tu trouvera ton probleme ^^


    EDIT :

    En fait, c'est juste parce que je n'avais pas le ttf ><
    Désolé.

    Mais j'ai bien une fuite de memoire lente dans cette partie du code.


    Ca y est, j'ai trouvé

    C'est parce que tu ne libere pas la Surface que te retourne TTF_RenderText_Solid.

    Il faut juste rajouter SDL_FreeSurface(texte[i]) après le blit !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
                                              for(i = 0; i < 20; i++)
                                              {
                                                            if(message[i] != "")
                                                            {
                                                                          texte[i] = TTF_RenderText_Solid(police, message[i], couleurFont);
                                                                          positionTexte.x = 10;
                                                                          positionTexte.y = TAILLE_FONT * 1.2 * (i+1);
                                                                          SDL_BlitSurface(texte[i], NULL, ecran, &positionTexte);
                                                                          SDL_FreeSurface(texte[i]);
                                                            }
                                              }

  5. #5
    Membre confirmé
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Juin 2006
    Messages
    122
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Juin 2006
    Messages : 122
    Par défaut
    @ Climoo :

    Je me suis un peu renseigné sur les logiciels, mais jusqu'ici je n'en ai trouvé aucun gratuit pour les fuites de mémoire en C. Il en éxiste un pour le C++ par contre.

    @ SofEvans :

    Merci pour les petites astuces. Ca fait moins sale pour l'initialisation de mon message[][], mais ma méthode marche aussi il me semble, en passant par un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for(i = 0; i < 20; i++)
         message[i] = "";
    pour faire plus propre, j'ai lus sur un cours que le char [...] = ""; initialise bien toute la chaine de caractère. =p

    Pour le while(SDL_PollEvent), j'ai pas encore bien saisie le principe, mais je vois bien l'effet que j'ai rencontré sur un ptit programme de test avec un SDL_Surface qui suis le curseur. En bougeant trop vite trop longtemps, la surface fini par se désynchro. :/

    Par contre, parce que j'ai pas saisie le principe, je dois fermer mon while où? =p juste après le traitement des event? Après les calcul ? Ou j'englobe tout sauf le calcul du FPS? =p

    Et Bingo pour le TTF_RenderText_Solid ! En effet, si je stop le mode debug avec F12 lorsque je lance le jeu, la fuite s'arrête complètement, la mémoire redevient stable...

    C'est impressionnant comme 1 SDL_FreeSurface oublié peux pomper autant de mémoire. :/

    Bon au moins, ça me rassure, j'ai l'air de manier correctement mes pointeurs. :p

    Merci beaucoup en tout cas pour ton aide SofEvans! Je pense que je l'aurai trouvé au bout de quelques jours de cheveux arrachés... :p

  6. #6
    Membre émérite Avatar de SofEvans
    Homme Profil pro
    Développeur C
    Inscrit en
    Mars 2009
    Messages
    1 084
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur C

    Informations forums :
    Inscription : Mars 2009
    Messages : 1 084
    Par défaut
    salut,

    Je suis en train de refaire plus ou moins ton code.
    Je te le passerai pour que tu puisse le comparer.

    j'ai lus sur un cours que le char [...] = ""; initialise bien toute la chaine de caractère. =p
    Ah ? Je ne me souvenai plus
    Pour le PollEvent, le while se referme apres le switch case.

    Si tu veux faire un code plus propre, tu peux supprimer toute les accolade inutile.

    Par exemple, si tu n'as qu'une instruction :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        if (testBidon)
        {
            variableBidon = 0;
        }
    devient

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        if (testBidon)
            variableBidon = 0;
    Voila, ca aere un peu plus

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

Discussions similaires

  1. J'ai un problème mémoire, mais pourquoi ?
    Par Titi41 dans le forum Débuter
    Réponses: 3
    Dernier message: 04/11/2008, 11h57
  2. Fuite mémoire? Mais où?
    Par Tuizi dans le forum C#
    Réponses: 24
    Dernier message: 27/02/2008, 10h02
  3. [Toujours fuite de mémoire, mais repéré]
    Par Gonath dans le forum C++
    Réponses: 4
    Dernier message: 06/03/2006, 00h01
  4. Réponses: 1
    Dernier message: 26/11/2005, 20h18
  5. [Execution] qtintf70.dll Mais pourquoi?
    Par Pedro dans le forum EDI
    Réponses: 4
    Dernier message: 03/06/2004, 13h23

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