2017-07-21 5 views
1

J'essaie de comprendre pourquoi le programme suivant perd de la mémoire. Quand je regarde la taille du tas en utilisant la commande more /proc/<pid>/smaps, je peux voir que le tas ne cesse de croître. Il semble que le XtDestroyWidget ne libère pas vraiment la mémoire. Je serais très reconnaissant si quelqu'un peut me dire pourquoi cela se produit et me montrer la bonne façon de recréer des widgets. Merci d'avance!X Toolkit: le tas croît lorsque vous recréer des widgets

/* Compile on Solaris: cc widgets_mem.c -lXm -lXt -lX11 */ 
/* Compile on Linux: gcc -m32 widgets_mem.c -lXm -lXt -lX11 */ 

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <X11/keysymdef.h> 

#include <Xm/MainW.h> 
#include <Xm/PushB.h> 
#include <Xm/Form.h> 


Widget  toplevel; 
Widget  w_main; 
Widget  w_bb; 
Widget  w_button = NULL; 

Window  root_win; 
XtAppContext app; 
int  screen_number; 
Display  *display = NULL; 

void recreateWidgets() 
{ 
    printf ("recreating widgets\n"); 
    XtDestroyWidget (w_button); 

    w_button = XtVaCreateManagedWidget (
    "button", 
    xmPushButtonWidgetClass, w_bb, 
    XmNfillOnArm, False, 
    XmNhighlightThickness, 0, 
    XmNborderWidth, 1, 
    XmNmarginTop, 1, 
    XmNmarginWidth, 2, 
    XmNmarginHeight, 0, 
    XmNwidth, 20, 
    XmNheight, 10, 
    XmNrecomputeSize, False, 
    XmNalignment, XmALIGNMENT_CENTER, 
    NULL); 
} 


void main (int argc, char **argv) 
{ 
    XEvent event; 

    toplevel = XtVaAppInitialize (&app, "Mem leak test", 
        NULL, 0, &argc, argv, NULL, NULL); 
    display = XtDisplay (toplevel); 
    screen_number = DefaultScreen (display); 
    root_win = RootWindow (display, screen_number); 

    w_main = XtVaCreatePopupShell (
    "main", 
    topLevelShellWidgetClass, toplevel, 
    XmNgeometry, "-0+0", 
    XmNborderWidth, 0, 
    XmNshadowThickness, 0, 
    XmNminWidth, 1, 
    XmNmwmDecorations, 0, 
    XmNmwmFunctions, 0, 
    XmNwidth, 600, 
    XmNheight, 200, 
    NULL); 

    w_bb = XtVaCreateManagedWidget (
    "", 
    xmBulletinBoardWidgetClass, w_main, 
    XmNborderWidth, 4, 
    XmNshadowThickness, 0, 
    XmNmarginWidth, 0, 
    XmNmarginHeight, 0, 
    XmNx, 0, 
    XmNy, 0, 
    XmNwidth, 500, 
    XmNheight, 100, 
    NULL); 

    w_button = XtVaCreateManagedWidget (
    "button", 
    xmPushButtonWidgetClass, w_bb, 
    XmNfillOnArm, False, 
    XmNhighlightThickness, 0, 
    XmNborderWidth, 1, 
    XmNmarginTop, 1, 
    XmNmarginWidth, 2, 
    XmNmarginHeight, 0, 
    XmNwidth, 20, 
    XmNheight, 10, 
    XmNrecomputeSize, False, 
    XmNalignment, XmALIGNMENT_CENTER, 
    NULL); 

    XtPopup (w_main, XtGrabNone); 

    while (1) 
    { 
     XtAppNextEvent (app, &event); 
     if (event.type == ButtonPress) 
     { 
      printf ("Button pressed, recreating widgets\n"); 
      recreateWidgets(); 
     } 
    } 
} 
+1

Notez que lorsque la mémoire est libérée, elle n'est pas retournée aux o/s; il est conservé par le système de gestion de la mémoire pour réutilisation. Si vous libérez un widget, l'espace utilisé peut être utilisé par le widget suivant créé. Donc, ça pourrait être qu'il n'y a pas de problème. OTOH, si votre programme se bloque avec un manque de mémoire, vous avez une fuite qui doit être réparée. –

+0

Sous Linux et Solaris, 'void main()' est inconditionnellement incorrect. Le type de retour de 'main()' est 'int'. Seulement sur Windows pouvez-vous demander une exemption de cela, et vous n'êtes pas sur Windows. Les compilateurs modernes à mi-chemin s'en plaindraient. Vous n'utilisez pas suffisamment d'avertissements de compilation. –

+1

Si vous pensez que votre programme perd de la mémoire, je vous suggère d'utiliser [valgrind] (http://valgrind.org/), [dmalloc] (http://dmalloc.com/) ou [efence] (http : //elinux.org/Electric_Fence). – Bass

Répondre

0

J'ai trouvé le bug dans mon code: je devais ajouter un XtDispatchEvent (événement &), qui gère les désaffecter des widgets qui sont sur la liste de destory, une liste interne Xt.