[SDL] Fuite mémoire

Répondre
Partager Rechercher
Hello le labo!
Je reviens vers vous pour un problème de fuite mémoire.

En effet, avec un groupe de 4 amis, on fait un jeu en SDL pour un projet de fac.
J'utilise donc un PollEvent, et je me rend compte que le programme utilise 10Mo de plus chaque seconde. ça fait vite beaucoup ^^

Je pense avoir identifié la fonction responsable :
Code:
void afficheBarreVie(T_Heros heros, SDL_Surface* ecran)
{
      SDL_FreeSurface( barreVie);
      SDL_Surface* barreVie = SDL_CreateRGBSurface(SDL_HWSURFACE, heros->vie*2, 20, 32, 0, 0, 0, 0);
      SDL_FillRect(barreVie, NULL, SDL_MapRGB(ecran->format, 255, 0, 0));
      SDL_BlitSurface(barreVie, NULL, ecran, &positionBarreVie);
}
Quand je commente cette fonction, la mémoire reste stable. Du coup j'imagine que ça vient d'ici. En revanche je ne vois pas pourquoi cette fonction est incriminée, vu que je fais bien un free(barreVie) avant chaque réallocation. Du coup je suis assez perplexité :/

Une idée?
Code:
SDL_FreeSurface( barreVie); 
 SDL_Surface* barreVie = ...
Je crois que tu as deux pointeurs différents : un barreVie extérieur à la fonction en paramètre de SDL_FreeSurface, et ensuite un deuxième déclaré en local. Le premier vaut null passé le premier appel et SDL_FreeSurface ne libère rien.

Ca devrait marcher comme ça :
Code:
SDL_FreeSurface( barreVie); 
 barreVie = ...
Genzz a du trouvdf le problème.
Tu crée bien une deuxième barre vie locale.

Tu dois donc modifier ton programme de façon à ne pas libérer la surface à ce moment.
Cette libération doit s'effectuer à la fin de ton programme c'est le fonctionnement habituel il me semble.

Donc :
Code:
barreVie->w = heros->vie*2
SDL_BlitSurface(barreVie, NULL, ecran, &positionBarreVie);
Et la barre de vie doit être crée précédemment.

EDIT : Ah c'est déconseillé oublié u_U.

Donc il te faut recréer une surface d'une largeur différente.
Et la libérer à la fin de la fonction.

Code:
SDL_Surface* barreVie = SDL_CreateRGBSurface(SDL_HWSURFACE, heros->vie*2, 20, 32, 0, 0, 0, 0);
  SDL_FillRect(barreVie, NULL, SDL_MapRGB(ecran->format, 255, 0, 0));       
SDL_BlitSurface(barreVie, NULL, ecran, &positionBarreVie);
SDL_FreeSurface( barreVie);

Dernière modification par Yame ; 22/03/2014 à 20h57.
mmmh mais du coup le problème, c'est que c'est mon moyen d'afficher la barre de vie de façon dynamique! En gros à chaque fois que je prends des dégats, le createRGBSurface crée une barre plus courte.

ton bout de code ne permet pas ça!
Citation :
Publié par Yame
Oui .
avec ça :

Code:
void afficheBarreVie(T_Heros heros, SDL_Surface* ecran)
{
      SDL_Surface * barreVie = SDL_CreateRGBSurface(SDL_HWSURFACE, heros->vie*2, 20, 32, 0, 0, 0, 0);
      SDL_FillRect(barreVie, NULL, SDL_MapRGB(ecran->format, 255, 0, 0));
      SDL_BlitSurface(barreVie, NULL, ecran, &positionBarreVie);
      SDL_FreeSurface( barreVie);
}
mon programme compile, mais plante :[
Ah oui, je redoutais la libération avant d'afficher l'écran.

EDIT :
A tout hasard
Code:
 barreVie = SDL_CreateRGBSurface(SDL_HWSURFACE, heros->vie*2, 20, 32, 0, 0, 0, 0);
ne fonctionne t'il pas ?
Avec le premier code.

Parce que tu avais dit qu'il oubliait que c"était une surface mais en y repensant j'ai du mal à y croire.
Et j'avais proposé un tableau l'histoire de conserver le type mais c'est sans doute pas nécessaire.

Dernière modification par Yame ; 22/03/2014 à 21h14.
avec ceci
Code:
void afficheBarreVie(T_Heros heros, SDL_Surface* ecran)
{
      SDL_FreeSurface(barreVie);
      barreVie = SDL_CreateRGBSurface(SDL_HWSURFACE, heros->vie*2, 20, 32, 0, 0, 0, 0);
      SDL_FillRect(barreVie, NULL, SDL_MapRGB(ecran->format, 255, 0, 0));
      SDL_BlitSurface(barreVie, NULL, ecran, &positionBarreVie);
}
ça compile, mais ça bug.


Avec ceci :
Code:
void afficheBarreVie(T_Heros heros, SDL_Surface* ecran)
{
      SDL_FreeSurface(barreVie);
      *barreVie = SDL_CreateRGBSurface(SDL_HWSURFACE, heros->vie*2, 20, 32, 0, 0, 0, 0);
      SDL_FillRect(barreVie, NULL, SDL_MapRGB(ecran->format, 255, 0, 0));
      SDL_BlitSurface(barreVie, NULL, ecran, &positionBarreVie);
}
ça ne compile pas!
Citation :
Publié par Yame
Quel est le bug ?

Et désolé pour le * et le & je suis pas habitué à la SDL et au C donc niveau pointeur j'ai plus l'habitude :c.
Le bug, c'est que après la première utilisation, le programme oublie que barreVie est un SDL_surface*, du coup quand on lui attribue un rgbsurface, il quitte le programme (*** a cessé de fonctionner).
Warning: je n'ai pas l'habitude la sdl. Maintenant dans ton truc (hors le problème initial ou tu avais effectivement une variable globale et une locale à ta fonction):

- globalement dans un jeu, dans la boucle d'affichage on évite de créer des surfaces à tout va, les allocations mémoire ça te flingue les performances. Tu créer tes surfaces à l'initialisation du niveau/jeu, tu stocke ça soit en variables globales, soit dans une structure que tu filera à tes fonctions, et tu fais le nettoyage à la fin (c'est valable pour toutes les allocations mémoires globalement, pas seulement les surfaces).

- tout bêtement ce que tu veux faire c'est afficher un rectangle plein sur ta surface écran non?

Du coup te méthode ne ressemblerait pas tout simplement à:

Code:
void afficheBarreVie(T_Heros heros, SDL_Surface* ecran)
{
      SDL_Rect rect;
      rect.x = positionBarreVie.x;
      rect.y = positionBarreVie.y;
      rect.w = heros->vie*2;
      rect.h = 20; // PS: met toute tes valeurs magiques dans le genre dans des constantes
      SDL_FillRect(ecran, &rect, SDL_MapRGB(ecran->format, 255, 0, 0));
}
Pourquoi passer par une surface intermédiaire?
Ah désolé je pensais pas qu'on pouvait faire oublier un type.

Mais c'est du C donc y a pas de vector donc pas de suppression de la surface libéré pour remettre une belle surface avec un type.

Bon, je pense que tu devrais avoir la réponse par quelqu'un qui connait une solution propre.

EDIT : Bah c'est fait .

Bravo Chagarou.
Citation :
Publié par Chagarou
Warning: je n'ai pas l'habitude la sdl. Maintenant dans ton truc (hors le problème initial ou tu avais effectivement une variable globale et une locale à ta fonction):

- globalement dans un jeu, dans la boucle d'affichage on évite de créer des surfaces à tout va, les allocations mémoire ça te flingue les performances. Tu créer tes surfaces à l'initialisation du niveau/jeu, tu stocke ça soit en variables globales, soit dans une structure que tu filera à tes fonctions, et tu fais le nettoyage à la fin (c'est valable pour toutes les allocations mémoires globalement, pas seulement les surfaces).

- tout bêtement ce que tu veux faire c'est afficher un rectangle plein sur ta surface écran non?

Du coup te méthode ne ressemblerait pas tout simplement à:

Code:
void afficheBarreVie(T_Heros heros, SDL_Surface* ecran)
{
      SDL_Rect rect;
      rect.x = positionBarreVie.x;
      rect.y = positionBarreVie.y;
      rect.w = heros->vie*2;
      rect.h = 20; // PS: met toute tes valeurs magiques dans le genre dans des constantes
      SDL_FillRect(ecran, &rect, SDL_MapRGB(ecran->format, 255, 0, 0));
}
Pourquoi passer par une surface intermédiaire?


La je suis obligé de recréer la rgbsurface, parce que je dois la changer! ma surface est proportionnelle aux points de dégats du héros, du coup je dois être capable de la changer à tout moment!

Et du coup avec ta solution, ma surface reste toujours la même!
Non avec ma solution et si ne me trompe pas sur la façon de fonctionner de la sdl, je dessine un rectangle dont la taille dépend des hp de ton héros directement sur la surface écran.

CF:
http://wiki.libsdl.org/SDL_FillRect

Le paramètre du milieu est pas la pour rien.

En comparaison, toi tu créer un surface de la taille de ta barre, tu la remplis avec une couleur et tu la blit à l'endroit voulu. Alors que tu veux juste remplir un rectangle avec une couleur pleine. Ce que fais à vu de nez SDL_FillRect tout seul, si on lui file les bonnes coordonnées.
Normalement, tu change les points vies à un endroit où tu effectue la logique de ton jeu.

Puis tu affiches tout, dans un autre endroit.
Donc afficheBarreVie pou chaque heros.

Si heros->vie change, la barre crée aura une taille différente le rectangle sera différent.
Citation :
Publié par Chagarou
Non avec ma solution et si ne me trompe pas sur la façon de fonctionner de la sdl, je dessine un rectangle dont la taille dépend des hp de ton héros directement sur la surface écran.

CF:
http://wiki.libsdl.org/SDL_FillRect

Le paramètre du milieu est pas la pour rien.

En comparaison, toi tu créer un surface de la taille de ta barre, tu la remplis avec une couleur et tu la blit à l'endroit voulu. Alors que tu veux juste remplir un rectangle avec une couleur pleine. Ce que fais à vu de nez SDL_FillRect tout seul, si on lui file les bonnes coordonnées.
omg YES!
J'ai pas pensé à remplacer ce sdl_rect qui reste à NULL la plupart du temps!
Excellent! Merci bien :')
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés