Partage
  • Partager sur Facebook
  • Partager sur Twitter

[SDL] Libérer de la mémoire, sans libérer la surface?

Sujet résolu
    18 septembre 2007 à 23:17:00

    Salut à tous :p .
    Je postes ce court message, car j'ai actuellement un problème dans la conception d'une classe Sprite (classe basée sur SDL et censée simplifier les routines de bases, avec l'ajout de gestion d'animation, et autres effets supplémentaires).

    Jusqu'à présent, ma classe fonctionne nickel, cependant, j'ai une méthode "LoadBMP" (j'implémenterai les autres formats plus légers plus tard) qui charge une image dans la surface membre du Sprite (sous forme d'un SDL_Surface* membre) et effectue des opérations supplémentaires.
    Le seul problème, est que bien que le sprite ne comporte qu'une seule surface, lorsque je remplace celle-ci, la mémoire n'est pas libérée, mais la surface oui (confirmé par l'affichage à l'écran).

    Normal vous me direz, il faut utiliser SDL_FreeSurface() pour cela. Le problème est que lorsque je met ça, mon prog fonctionne une fois, mais dés le deuxième passage plante (soit, ça semble signifier que le membre SDL_Surface* n'existe plus). J'ai essayé de transformer mon membre en pointeur vers un SDL_Surface*, de le reallouer après la libération, mais rien à faire, j'obtiens le même résultat et je semble avoir perdu le focus de la surface...

    Pour des raisons de performances, je préfère charger la surface et la stocker en mémoire jusqu'à ce qu'elle soit inutile, plutôt que de la recharger à chaque fois via une autre méthode (d'où l'utilisation de SDL_FreeSurface restreinte dans ce cas présent).

    Du coup, soit je me retrouve avec une fuite mémoire impressionnante o_O , soit mon programme plante lamentablement :colere2: .
    Je viens donc ici vous demander s'il y a une méthode préconisée pour simplement libérer une surface :) , sans pour autant la supprimer, car j'ai bien l'impression que SDL_FreeSurface est stricte sur ce point là :-° .

    Merci d'avance ;)

    PS:Si jamais vous voulez voir mon code, n'hésitez pas.
    • Partager sur Facebook
    • Partager sur Twitter
      18 septembre 2007 à 23:29:29

      faut mettre ses pointeurs à NULL, par exemple :
      1. class Sprite {
      2. public:
      3.     Sprite() { m_image = NULL; };
      4.     void load( char* img ) {
      5.         if( m_image != NULL)
      6.             SDL_FreeSurface( m_image );
      7.         m_image = SDL_LoadBMP( img );
      8.     };
      9. private:
      10.     SDL_Surface* m_image;
      11. };
      • Partager sur Facebook
      • Partager sur Twitter
        20 septembre 2007 à 17:46:43

        Salut à toi :p , et désolé pour le retard :-° (a peine passé la rentrée, et on se retrouve avec une montagne de trucs à faire...)

        J'avais déjà testé une alternative, proche de la tienne, ce sans succès, de même que ta méthode :colere2: .
        En effet, dans ta solution, le sprite est libéré seulement si son pointeur n'est pas nul; or s'il est nul, j'ai déjà perdu le focus sur la mémoire utilisée pour stocker la Surface qu'il contenait, du coup la mémoire ne peut plus être libérée.
        Dans le cas ou je libère la surface tout court, je perds complètement le focus sur le pointeur même, qui n'existe alors plus (erreur de type Segmentation fault).

        Etant donné que je compte mettre en place un système d'animation sur plusieurs surface ( à l'instar des bmp contenant chaque frame étalé sur une banderole), et que j'aurais certainement besoin d'un vector de SDL_Surface (je ne me suis pas encore trop penché sur les vectors, mais d'après ce que j'ai lu ça semble adapté à ce que je cherches faire : un tableau dynamique), je devrais pouvoir contourner le problème actuel, bien que j'aurais bien aimé résoudre le problème qui se pose actuellement...

        En tout cas, merci pour ta réponse ;)
        • Partager sur Facebook
        • Partager sur Twitter
          20 septembre 2007 à 19:10:25

          Je ne comprends pas trop cette histoire de focus.
          La solution donnée est bonne (pour te convaincre, essaye-là dans un code tout con).
          Tu dois perdre des pointeurs à un moment ou les libérer puis les utiliser avant de les allouer. Regarde dans ton code!
          Et si tu ne trouves rien, poste-le ici ou s'il est trop gros, upload-le.
          • Partager sur Facebook
          • Partager sur Twitter
            20 septembre 2007 à 21:09:02

            Tu n'as pas compris. Je pense que tu ne peux pas libéré un pointeur NULL car il ne pointe tout simplement sur aucune parcelle de mémoire. Ton programme dois planter pour ça

            if( m_image != NULL)
            SDL_FreeSurface( m_image );
            • Partager sur Facebook
            • Partager sur Twitter
              20 septembre 2007 à 23:35:51

              En effet, je ne peux pas libérer un pointeur NULL, mais ce que je voulais dire c'est qu'en assignant mon pointeur à NULL, je n'ai aucun moyen de libérer la mémoire qu'il occupait auparavant.
              De même, je veux bien croire que le code donné est bon ^^ , cependant, juste après le SDL_FreeSurface, je ne peux plus redéfinir ma surface via le SDL_LoadBMP comme ce qui est préconisé (et que j'avais moi même mis initialement). Je penses qu'avec un autre type de données de "base" ça devrait marcher, cependant SDL_FreeSurface est tellement radical qu'il supprime tout.

              Donc soit, le pointeur n'était assigné à rien du tout, et là il charge correctement, mais dés qu'il cherche à libérer son contenu pour en prendre un autre (d'où le sujet de mon message et l'utilité de ma méthode censée automatiser tout cela), il me sort une segmentation fault, car SDL_FreeSurface semble supprimer complètement de la mémoire le pointeur utilisé (d'où le terme de focus que j'ai employé, pour dire qu'on le perds complètement de vue, sans possibilité d'y accéder, mais avec la place prise en mémoire comme preuve qu'il y est toujours).

              Jusqu'à présent, le code minimal que j'ai tapé est identique à celui déjà posté ici, à la seule différence que j'ai rajouté plus loin (ça n'influe en rien sur le problème actuel) une méthode de gestion de la transparence.
              Je ne sais pas si ça fonctionne chez vous donc (le code proposé), mais chez moi le SDL_FreeSurface, suivi d'un SDL_LoadBMP, ou n'importe quelle méthode faisant appel à un SDL_Surface* me renvoie à chaque fois une seg fault et une erreur de compil...
              • Partager sur Facebook
              • Partager sur Twitter
                21 septembre 2007 à 4:46:26

                bah, si j'ai bien compris (et j'en suis pas trop sûr), tu pourrais avoir un truc tout con comme ça (simplifié un peu) :

                1. if (laSurface == NULL)
                2.    laSurface = loadBMP("blabla.bmp");
                3. else {
                4.    SDL_FreeSurface(laSurface);
                5.    laSurface = loadBMP("blabla.bmp");
                6. }


                Citation : Pas de titre

                cependant, juste après le SDL_FreeSurface, je ne peux plus redéfinir ma surface via le SDL_LoadBMP comme ce qui est préconisé


                bah si, tu peux faire un loadBMP sur une surface après l'avoir vidé de la mémoire. o_O

                et celon moi, si ça te sort un segmentation fault, c'est parce que t'essaie de faire un SDL_FreeSurface sur "laSurface" qui est égal à NULL.

                et enfin, je comprend ton affaire de focus, mais je ne crois pas que cela arrive...

                ... aussi, pour qu'on puisse mieux t'aider, post ton code, ou du moins la partie en question. :p
                • Partager sur Facebook
                • Partager sur Twitter
                Altarapp.com - Applications, Code Snippets, API Wrappers et etc, le tout en C# le plus clair du temps!
                  21 septembre 2007 à 20:56:01

                  Citation : k4dw4

                  Tu n'as pas compris. Je pense que tu ne peux pas libéré un pointeur NULL car il ne pointe tout simplement sur aucune parcelle de mémoire. Ton programme dois planter pour ça

                  if( m_image != NULL)
                  SDL_FreeSurface( m_image );


                  Ben non puisque ce programme ne libère le pointeur que s'il est différent de NULL. Don s'il n'est pas NULL et qu'il a bien été initialisé, ça ne plante pas.
                  Montre toujours ton code, tu peux avoir un problème de transparence (sur une surface vide par exemple).
                  • Partager sur Facebook
                  • Partager sur Twitter
                    21 septembre 2007 à 23:35:17

                    Voila le code, comme demandé ;) :

                    1. void Sprite::LoadBMP(std::string file, bool transparent, Uint8 r, Uint8 g, Uint8 b)
                    2. {
                    3.     if(m_sprite_surface != NULL)
                    4.         SDL_FreeSurface(m_sprite_surface);
                    5.     m_sprite_surface = SDL_LoadBMP(file.c_str());
                    6.     if(m_sprite_surface != NULL)
                    7.     {
                    8.         m_sprite_file= file;
                    9.         if(transparent)
                    10.             SDL_SetColorKey ( m_sprite_surface, SDL_SRCCOLORKEY, SDL_MapRGB( m_sprite_surface->format, r , g , b));
                    11.     }
                    12. }


                    Et ma classe Sprite:

                    1. class Sprite
                    2. {
                    3. public:
                    4. /*Construction*/
                    5. Sprite(std::string, bool = false, Uint8 = 255, Uint8 = 0, Uint8 = 255);
                    6. Sprite(const Sprite&);
                    7. /*Fonctions actives*/
                    8. void LoadBMP(std::string, bool = false, Uint8 = 255, Uint8 = 0, Uint8 = 255);
                    9. void SetPos(int,int);
                    10. void SetX(int);
                    11. void SetY(int);
                    12. void Render(SDL_Surface*);
                    13. SDL_Surface* &GetSurface();
                    14. /*Fonctions passives*/
                    15. inline std::string GetFile() { return m_sprite_file; };
                    16. inline int GetX() { return m_sprite_position.x; };
                    17. inline int GetY() { return m_sprite_position.y; };
                    18. private:
                    19. SDL_Surface* m_sprite_surface;
                    20. SDL_Rect m_sprite_position;
                    21. std::string m_sprite_file;
                    22. };


                    C'est donc presque identique (ou dumoins à mes yeux, alors corrigez moi si je me trompes :-° ) au code posté en exemple, qui de plus est censé fonctionner. Cependant, j'ai toujours ce problème de segmentation fault, qui selon vous n'a rien à faire dans mon cas présent, et je ne vois pas moi même d'où ça pourrait bien venir.

                    En tout cas, merci pour l'intêret que vous portez à mon problème ;) .
                    • Partager sur Facebook
                    • Partager sur Twitter
                      22 septembre 2007 à 10:32:59

                      1. #include <SDL/SDL.h>
                      2. #include <string>
                      3. class Sprite
                      4. {
                      5. public:
                      6. /*Construction*/
                      7. Sprite(){m_sprite_surface=NULL;}
                      8. /*Fonctions actives*/
                      9. void LoadBMP(std::string, bool = false, Uint8 = 255, Uint8 = 0, Uint8 = 255);
                      10. void Render(SDL_Surface* s){SDL_BlitSurface(m_sprite_surface,NULL,s,NULL);}
                      11. private:
                      12. SDL_Surface* m_sprite_surface;
                      13. SDL_Rect m_sprite_position;
                      14. std::string m_sprite_file;
                      15. };
                      16. void Sprite::LoadBMP(std::string file, bool transparent, Uint8 r, Uint8 g, Uint8 b)
                      17. {
                      18.     if(m_sprite_surface != NULL)
                      19.         SDL_FreeSurface(m_sprite_surface);
                      20.     m_sprite_surface = SDL_LoadBMP(file.c_str());
                      21.     if(m_sprite_surface != NULL)
                      22.     {
                      23.         m_sprite_file= file;
                      24.         if(transparent)
                      25.             SDL_SetColorKey ( m_sprite_surface, SDL_SRCCOLORKEY, SDL_MapRGB( m_sprite_surface->format, r , g , b));
                      26.     }
                      27. }
                      28. int main(int argc, char **argv){
                      29.     SDL_Init(SDL_INIT_VIDEO);
                      30.     SDL_Surface *ecran=SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE);
                      31.     Sprite s;
                      32.     s.LoadBMP("01.bmp",false,0,0,0);
                      33.     s.Render(ecran);
                      34.     SDL_Flip(ecran);
                      35.     bool done=0;
                      36.     while (!done){
                      37.         SDL_Event event;
                      38.         while (SDL_PollEvent(&event)){
                      39.             if (event.type==SDL_QUIT)done=1;
                      40.         }
                      41.     }
                      42.     SDL_FillRect(ecran,NULL,SDL_MapRGB(ecran->format,0,0,0));
                      43.     s.LoadBMP("01.bmp",true,0,0,0);
                      44.     s.Render(ecran);
                      45.     SDL_Flip(ecran);
                      46.     done=0;
                      47.     while (!done){
                      48.         SDL_Event event;
                      49.         while (SDL_PollEvent(&event)){
                      50.             if (event.type==SDL_QUIT)done=1;
                      51.         }
                      52.     }
                      53.     SDL_Quit();
                      54.     return 0;
                      55. }

                      Ceci marche parfaitement.
                      Il y a un bug dans un autre endroit de ton code.
                      1. printf("Ok");
                      2. fflush(stdout);

                      Mets ça ou son équivalent en C++, à différents endroits de ton code et regarde ce que te donne la sortie (stdout.txt).
                      • Partager sur Facebook
                      • Partager sur Twitter
                        22 septembre 2007 à 14:51:47

                        Salut à tous, et premièrement, je penses avoir résolu le problème ^^ , bien que je ne vois pas en quoi ce que j'ai fais aurait changé quoique ce soit...

                        J'avais déjà utilisé le coup des couts et printf pour déceler la source du problème, et c'est ça semble toujours se poser au niveau du SDL_LoadBMP, voila, avec les commentaires:

                        1. void Sprite::LoadBMP(std::string file, bool transparent, Uint8 r, Uint8 g, Uint8 b)
                        2. {
                        3.     if(m_sprite_surface != NULL)
                        4.     {
                        5.         std::cout<<"liberation de la surface"<<std::endl;
                        6.         SDL_FreeSurface(m_sprite_surface);
                        7.         std::cout<<"surface libere"<<std::endl;
                        8.     }
                        9.     std::cout<<"chargement du bmp"<<std::endl;
                        10.     m_sprite_surface = SDL_LoadBMP(file.c_str());
                        11.     std::cout<<"bmp charge"<<std::endl;
                        12.     if(m_sprite_surface != NULL)
                        13.     {
                        14.         m_sprite_file= file;
                        15.         if(transparent)
                        16.             SDL_SetColorKey ( m_sprite_surface, SDL_SRCCOLORKEY, SDL_MapRGB( m_sprite_surface->format, r , g , b));
                        17.     }
                        18. }


                        Et ce que ça m'affiche en sortie:

                        liberation de la surface
                        surface libere
                        chargement du bmp
                        bmp charge
                        liberation de la surface
                        surface libere
                        chargement du bmp
                        Press ENTER to continue.


                        La première boucle, qui correspond à l'initialisation, donc avec le pointeur supposément null, mais la méthode vide quand même la surface (la source du problème à priori :-° )quand même la surface. Ensuite il charge correctement l'image, et passe à la prochaine boucle, avec suppression de la surface. Sauf que cette fois-ci il plante au chargement du bmp.

                        Je ne sais pas trop en quoi ce que j'ai modifié aurait pu régler le problème de mémoire à ce niveau là (puisqu'il passe la première boucle), mais j'ai tout simplement initialisé mon pointeur vers la surface à NULL dans le constructeur, avant de faire appel à la méthode ci-dessus (chargement de bmp).

                        Du coup, ça marche à présent, et je n'ai plus ce dépassement assourdissant de mémoire ^^

                        En tout cas, merci beaucoups pour votre aide ;) !!
                        • Partager sur Facebook
                        • Partager sur Twitter
                          26 septembre 2007 à 21:08:46

                          Citation : Pole

                          Citation : k4dw4

                          Tu n'as pas compris. Je pense que tu ne peux pas libéré un pointeur NULL car il ne pointe tout simplement sur aucune parcelle de mémoire. Ton programme dois planter pour ça

                          if( m_image != NULL)
                          SDL_FreeSurface( m_image );


                          Ben non puisque ce programme ne libère le pointeur que s'il est différent de NULL. Don s'il n'est pas NULL et qu'il a bien été initialisé, ça ne plante pas.
                          Montre toujours ton code, tu peux avoir un problème de transparence (sur une surface vide par exemple).



                          J'ai mis la solution et non le problème. Dans le code original, je pense qu'il n'y a pas de vérification..
                          • Partager sur Facebook
                          • Partager sur Twitter

                          [SDL] Libérer de la mémoire, sans libérer la surface?

                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                          • Editeur
                          • Markdown