Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 23/07/2010, à 23:19

Bigcake

[Résolu]Fuite de mémoire avec setjmp et longjmp en C / libX

Bonjour,

J'ai un petit problème de fuite de mémoire dans mon programme à cause de setjmp et longjmp (enfin je pense que c'est la cause principale)
J'ai une perte de 20 a 24 Ko à chaque fois.
Le code qui suis réagit en gros comme mon programme et permet de voir la fuite.

gcc -o test main.c -L/usr/X11R6/lib -lX11

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <unistd.h>
#include <X11/Xlib.h>

Window    win;
jmp_buf   IOErrorJump;

int            IOErrorHandler(Display *dpy)
{
  /* XUnmapWindow(dpy, win);   */
  /* XDestroyWindow(dpy, win); */
  XCloseDisplay(dpy);
  longjmp(IOErrorJump, 0);
}

int              main(int ac, char **av)
{
  Display        *dpy;
  char           buff[2];

  XSetIOErrorHandler(IOErrorHandler);
  setjmp(IOErrorJump);
  while (1) {
    dpy = XOpenDisplay(0);
    printf("fd = %d\n", ConnectionNumber(dpy));
    win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 150, 150, 150, 150, 0, 0, 0xf7f5df);
    XMapWindow(dpy, win);
    XFlush(dpy);
    read(0, buff, 1);
    XCloseDisplay(dpy);
  }
  return (0);
}

Si on appuie sur 'Enter' la fenêtre se ferme et se recréer, pas de fuite de mémoire
Si on ferme la fenêtre avec le bouton du WM, on appuie sur 'enter', la fenêtre se recréer, perte de 20 a 24Ko

J'ai remarqué que le file descriptor correspondant à la connexion au serveur X reste ouvert alors qu'il devrai être fermé avec XCloseDisplay()

Si vous avez une idée pour régler cette fuite ou alors gérer la fermeture de la fenêtre autrement que la façon dont je procède, je suis preneur de toute idée (à part changer de librairie tongue).
Merci.

Dernière modification par Bigcake (Le 25/07/2010, à 00:40)


"Les gens" ne sont pas cons, ils ont été habitués à la facilité et à la désinformation. Le meilleur moyen de ne pas les aider, c'est de se moquer. Le meilleur moyen de les aider, c'est de les informer, encore et encore. La réflexion viendra. N'oubliez pas que vous aussi, vous êtes le con d'un autre.
Smartphone+GNU/Linux=Librem5

Hors ligne

#2 Le 24/07/2010, à 11:19

grim7reaper

Re : [Résolu]Fuite de mémoire avec setjmp et longjmp en C / libX

Salut,

Bon déjà, normalement ta fonction IOErrorHandler() est inutile car ce code que tu as posté ne doit pas générer d'erreur (du moins si tout est bien géré wink).
Une question : pourquoi n'utilise tu pas la gestion des évenements intégrée à la Xlib ?
C'est quand même plus propre qu'un read.

Au sujet des fuites de mémoire, comment les détectes-tu ?
Valgrind (avec l'outil memcheck) je suppose. Il faut savoir qu'il détecte parfois des faux-positifs, ce ne sont pas des fuites de mémoires mais des fonctionnalités.
C'est peut-être le cas ici.
Un exemple connu est le C++ avec certaines implémentation de la STL qui utilisent leurs propres espaces d'allocations afin d'optimiser les performances.
Ces faux-positifs sont en général facile à repérer car la quantité de mémoire "perdue" est constante quelque soit les actions que tu réalises.

Si vous avez une idée pour régler cette fuite ou alors gérer la fermeture de la fenêtre autrement que la façon dont je procède

Oui, il faudrait passer par une gestion via XEvent (avec un soupçon d'XAtoms lors de la création de ta fenêtre pour éviter une erreur du type XIO: fatal IO error 11 (Resource temporarily unavailable) quand on utilise la "croix" ou son équivalent).

Dernière modification par grim7reaper (Le 24/07/2010, à 11:22)

Hors ligne

#3 Le 24/07/2010, à 22:15

Bigcake

Re : [Résolu]Fuite de mémoire avec setjmp et longjmp en C / libX

Tout d'abord, merci pour te pencher sur le problème ^^

Donc en fait c'est quand l'utilisateur ferme la fenêtre (avec le bouton fermer en haut à droite ou gauche tongue) que ma fonction IOErrorHandler() est appelé.

Pour le read, je l'ai juste rajouté pour pouvoir avoir une pause qui permette de fermer manuellement la fenêtre.

Pour la détection de la fuite de mémoire, j'utilise tous simplement l'équivalent du gestionnaire des taches de kde, je voit qu'a chaque fois que je recréer la connexion au serveur X et la fenêtre, mon processus gagne 20 à 24 Ko

Dans mon vrai programme, j'utilise XEvent pour gérer les évènements mais le problème c'est qu'il ne permet pas de gérer la fermeture des fenêtres par l'utilisateur.

J'ai déjà vu ce terme d'XAtoms sans trop savoir ce que c'est exactement, je vais essayer de trouver des truc las dessus.

Dernière modification par Bigcake (Le 24/07/2010, à 22:21)


"Les gens" ne sont pas cons, ils ont été habitués à la facilité et à la désinformation. Le meilleur moyen de ne pas les aider, c'est de se moquer. Le meilleur moyen de les aider, c'est de les informer, encore et encore. La réflexion viendra. N'oubliez pas que vous aussi, vous êtes le con d'un autre.
Smartphone+GNU/Linux=Librem5

Hors ligne

#4 Le 24/07/2010, à 22:57

grim7reaper

Re : [Résolu]Fuite de mémoire avec setjmp et longjmp en C / libX

Bigcake a écrit :

Tout d'abord, merci pour te pencher sur le problème ^^

Donc en fait c'est quand l'utilisateur ferme la fenêtre (avec le bouton fermer en haut à droite ou gauche tongue) que ma fonction IOErrorHandler() est appelé.

Oui, car ta fenêtre se ferme "mal" (voir explication plus loin). Je ne sais pas si ta fuite est en rapport avec ça.

Pour la détection de la fuite de mémoire, j'utilise tous simplement l'équivalent du gestionnaire des taches de kde, je voit qu'a chaque fois que je recréer la connexion au serveur X et la fenêtre, mon processus gagne 20 à 24 Ko

Utilise Valgrind, tu auras plus d'info (tu verras si le problème viens de toi, ou si c'est une "fonctionnalité" de la Xlib).

Dans mon vrai programme, j'utilise XEvent pour gérer les évènements mais le problème c'est qu'il ne permet pas de gérer la fermeture des fenêtres par l'utilisateur.

Si, mais c'est un peu plus compliqué. Voilà un bout de code qui le gère

switch(event.type)
{
    ...
    case ClientMessage :
        /* On regarde si le message correspond a WM_DELETE_WINDOW.
         * On teste "l" car les WM_PROTOCOLS sont codes sur 32 bits : 
         * http://tronche.com/gui/x/icccm/sec-4.html#s-4.4
         * et on teste la case 0 car c'est cette case qui contient le type 
         * de l'Atom : http://tronche.com/gui/x/icccm/sec-4.html#s-4.2.8 */
         if(event.xclient.data.l[0] == WM_DELETE_WINDOW)
         {
              puts("On a clique sur la croix");
         }
         break;
    ...
}

Bien sûr, il faut filer les flags adequats à la fonction XSelectInput() (bon je ne les ai plus en mémoire, mais go doc smile).

J'ai déjà vu ce terme d'XAtoms sans trop savoir ce que c'est exactement, je vais essayer de trouver des truc las dessus.

Les Atoms servent à communiquer.

Le problème vient du fait que ta premiere fenêtre est une descendante directe de la fenêtre "root" (On parle de fenêtre top-level). En tant que tel, elle a droit à un traitement spécial de la part du WM (Window Manager) et on ne peut donc pas la détruire sans prendre quelque précautions.
C'est d'ailleurs aussi pour cette raison que les paramètres "x" et "y" de la fonction XCreateSimpleWindow sont magnifiquement snobés. De même que le largeur de bordure que l'on souhaite.

http://www.sbin.org/doc/Xlib/chapt_03.html a écrit :

...
The basicwin application has only one window. Creating the first window of an application is a special case, because that window is a child of the root window and, therefore, is subject to management by the window manager. An application can suggest a position for this window, but it is very likely to be ignored. Most window managers allow the user to position the window as it appears on the screen. So most simple applications create the first window with its position set to (0,0).
...

Pour éviter ça, il va falloir communiquer avec le WM via les XAtoms WM_PROTOCOLS et lui demander d'ajouter (ce qui explique le PropModeAppend) la propriété WM_DELETE_WINDOW à la fenêtre pour pouvoir la fermer de maniere élégante (Pour les XAtoms voir http://www.sbin.org/doc/Xlib/chapt_12.html, pour le WM_DELETE_WINDOW voir http://tronche.com/gui/x/icccm/sec-4.html#s-4.2.8.1).
Une fois obtenu les précieux identifiants des XAtoms via les fonctions adéquates (XInternAtom) il n'y a plus qu'à appliquer les modifications et le tour est joué
(voir http://tronche.com/gui/x/xlib/window-in … nAtom.html, http://tronche.com/gui/x/xlib/window-in … perty.html et http://tronche.com/gui/x/icccm/sec-4.html#s-4.4).

Ça donne un truc comme ça

...
Window win = XCreateSimpleWindow(dpy,
                                 DefaultRootWindow(dpy),
                                 0, 0, WIDTH, HEIGHT, border_width,
                                 BlackPixel(dpy, DefaultScreen(dpy)),
                                 WhitePixel(dpy, DefaultScreen(dpy))
                                );
Atom WM_PROTOCOLS = XInternAtom(p_dpy, "WM_PROTOCOLS", 1);
Atom WM_DELETE_WINDOW = XInternAtom(p_dpy, "WM_DELETE_WINDOW", 1);
XChangeProperty(p_dpy, my_win, WM_PROTOCOLS, XA_ATOM, 32, PropModeAppend,
                (unsigned char *) &WM_DELETE_WINDOW, 1);
...

Maintenant, la fermeture de la fenêtre via la croix ne générera plus d'erreur XIO: fatal IO error 11 (Resource temporarily unavailable). Enfin normalement (chez moi en tout cas ^^) donc plus besoin de handle pour ça.

Tiens, voilà trois liens fort utiles (que tu connais peut-être déjà) lorsque l'on développe en Xlib :
- http://www.sbin.org/doc/Xlib/
- http://tronche.com/gui/x/xlib/
- http://tronche.com/gui/x/icccm/

Bon ça fait un moment que j'ai pas retouché à la Xlib donc des erreurs peuvent s'être glissées dans le pavé précédent, mais normalement la logique est là (en cas de doutes, la doc reste la référence smile).

Dernière modification par grim7reaper (Le 25/07/2010, à 10:50)

Hors ligne

#5 Le 24/07/2010, à 23:28

Bigcake

Re : [Résolu]Fuite de mémoire avec setjmp et longjmp en C / libX

wouahou ! Merci pour toutes ces infos je vais regarder ça !


"Les gens" ne sont pas cons, ils ont été habitués à la facilité et à la désinformation. Le meilleur moyen de ne pas les aider, c'est de se moquer. Le meilleur moyen de les aider, c'est de les informer, encore et encore. La réflexion viendra. N'oubliez pas que vous aussi, vous êtes le con d'un autre.
Smartphone+GNU/Linux=Librem5

Hors ligne