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

GTK+ avec C & C++ Discussion :

Fuites mémoire avec valgrind sur un exemple simple


Sujet :

GTK+ avec C & C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 16
    Points : 19
    Points
    19
    Par défaut Fuites mémoire avec valgrind sur un exemple simple
    Bonjour à tous,

    Pour comprendre comment utiliser Valgrind/Memcheck, j'ai pris ce petit programme qui ne fait rien sauf afficher un GtkTreeView dans une fenêtre.
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    #include <gtk/gtk.h>
     
    #define UI_FILE "/home/kazujoshi/test_treeview/test.ui"
     
    void create_treeview (GtkBuilder *builder)
    {
    	GtkWidget *treeview =
    		(GtkWidget *) gtk_builder_get_object (builder, "treeview1");
    	GtkCellRenderer *renderer;
    	GtkTreeViewColumn *id, *name;
    	GtkTreeViewColumn *day[31];
    	GtkListStore *store;
     
    	store = gtk_list_store_new (33,
    		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
    		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
    		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
    		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
    		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
    		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
    		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
    		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT,
    		G_TYPE_INT);
    	renderer = gtk_cell_renderer_text_new ();
     
    	id = gtk_tree_view_column_new_with_attributes ("id",
    		renderer,
    		"text",
    		0,
    		NULL);
     
    	name = gtk_tree_view_column_new_with_attributes ("name",
    	renderer,
    	"text",
    	1,
    	NULL);
    	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), name);
     
    	gint i;
    	gchar *title = NULL;
    	for (i = 0; i < 31; i++) {
    		title = g_strdup_printf (" %i ", i+1);
    		day[i] = gtk_tree_view_column_new_with_attributes (title,
    			renderer,
    			"text",
    			i+2,
    			NULL);
    		gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), day[i]);
    		g_free (title);
    	}
     
    	gtk_tree_view_set_model (GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(store));
    	gtk_tree_view_set_rules_hint (GTK_TREE_VIEW(treeview), TRUE);
    	g_object_unref (store);
    	}
     
    GtkWidget *create_window ()
    {
    	GError *error = NULL;
     
    	GtkBuilder *builder = gtk_builder_new ();
    	if (!gtk_builder_add_from_file (builder, UI_FILE, &error))
    	{
    		g_warning ("Couldn't load builder file : %s", error->message);
    		g_error_free (error);
    	}
     
    	GtkWidget *main_window =
    		(GtkWidget *) gtk_builder_get_object (builder, "window");
    	g_signal_connect (G_OBJECT (main_window),
    		"destroy", gtk_main_quit, NULL);
     
    	create_treeview (builder);
     
    	return main_window;
    }
     
    int main (int argc, char *argv[])
    {
    	GtkWidget *window;
     
    	gtk_set_locale ();
    	gtk_init (&argc, &argv);
     
    	window = create_window ();
    	gtk_widget_show (window);
     
    	gtk_main ();
     
    	return 0;
    }
    Le fichier text.ui est créé avec Glade :
    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
    <?xml version="1.0"?>
    <interface>
      <requires lib="gtk+" version="2.16"/>
      <!-- interface-naming-policy project-wide -->
      <object class="GtkWindow" id="window">
        <property name="default_width">440</property>
        <property name="default_height">250</property>
        <child>
          <object class="GtkTreeView" id="treeview1">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
          </object>
        </child>
      </object>
    </interface>
    J'utilise Valgrind en faisant :
    G_SLICE=always-malloc G_DEBUG=gc-friendly libtool --mode=execute valgrind --tool=memcheck --leak-check=full --show-reachable=yes --leak-resolution=high --num-callers=20 --log-file=vgdump_test /home/kazujoshi/test_treeview/test
    Le log retourné est très long donc je ne vais pas tout poster mais juste quelques lignes se rapportant à mes questions. Tout d'abord, voici le bilan :
    ==2135== LEAK SUMMARY:
    ==2135== definitely lost: 1,352 bytes in 7 blocks
    ==2135== indirectly lost: 4,636 bytes in 202 blocks
    ==2135== possibly lost: 12,243 bytes in 376 blocks
    ==2135== still reachable: 449,547 bytes in 6,608 blocks
    ==2135== suppressed: 0 bytes in 0 blocks
    ==2135==
    ==2135== For counts of detected and suppressed errors, rerun with: -v
    ==2135== ERROR SUMMARY: 201 errors from 201 contexts (suppressed: 132 from 13)
    Je ne comprends pas comment éviter les erreurs relatives au GtkBuilder :
    ==2135== 740 (36 direct, 704 indirect) bytes in 1 blocks are definitely lost in loss record 4,074 of 4,171
    ==2135== at 0x4023F50: malloc (vg_replace_malloc.c:236)
    ==2135== by 0x484CED3: g_malloc (in /lib/libglib-2.0.so.0.2400.1)
    ==2135== by 0x4862AB8: g_slice_alloc (in /lib/libglib-2.0.so.0.2400.1)
    ==2135== by 0x4862DB4: g_slice_alloc0 (in /lib/libglib-2.0.so.0.2400.1)
    ==2135== by 0x47E45C6: g_type_create_instance (in /usr/lib/libgobject-2.0.so.0.2400.1)
    ==2135== by 0x47C8907: ??? (in /usr/lib/libgobject-2.0.so.0.2400.1)
    ==2135== by 0x47CA079: g_object_newv (in /usr/lib/libgobject-2.0.so.0.2400.1)
    ==2135== by 0x47CA937: g_object_new (in /usr/lib/libgobject-2.0.so.0.2400.1)
    ==2135== by 0x413E8B6: gtk_builder_new (in /usr/lib/libgtk-x11-2.0.so.0.2000.1)
    ==2135== by 0x8048EBC: create_window (main.c:63)
    ==2135== by 0x8048F9C: main (main.c:87)
    Est-ce qu'une erreur de ce style est de mon ressort ? Valgrind renvoie pas mal d'erreurs relatives à des fonctions que je n'ai pas écrites, à pango, au xml, etc.
    ==2135== 160 (40 direct, 120 indirect) bytes in 1 blocks are definitely lost in loss record 3,924 of 4,171
    ==2135== at 0x4023F50: malloc (vg_replace_malloc.c:236)
    ==2135== by 0x49C7A03: nss_parse_service_list (nsswitch.c:622)
    ==2135== by 0x49C8146: __nss_database_lookup (nsswitch.c:164)
    ==2135== by 0x4030EAB: ???
    ==2135== by 0x4031F84: ???
    ==2135== by 0x49815A4: getpwnam_r@@GLIBC_2.1.2 (getXXbyYY_r.c:253)
    ==2135== by 0x487956D: ??? (in /lib/libglib-2.0.so.0.2400.1)
    ==2135== by 0x487B55C: g_get_home_dir (in /lib/libglib-2.0.so.0.2400.1)
    ==2135== by 0x424C217: ??? (in /usr/lib/libgtk-x11-2.0.so.0.2000.1)
    ==2135== by 0x424E8EA: ??? (in /usr/lib/libgtk-x11-2.0.so.0.2000.1)
    ==2135== by 0x41FA714: ??? (in /usr/lib/libgtk-x11-2.0.so.0.2000.1)
    ==2135== by 0x485378E: g_option_context_parse (in /lib/libglib-2.0.so.0.2400.1)
    ==2135== by 0x41FA30B: gtk_parse_args (in /usr/lib/libgtk-x11-2.0.so.0.2000.1)
    ==2135== by 0x41FA383: gtk_init_check (in /usr/lib/libgtk-x11-2.0.so.0.2000.1)
    ==2135== by 0x41FA3C3: gtk_init (in /usr/lib/libgtk-x11-2.0.so.0.2000.1)
    ==2135== by 0x8048F97: main (main.c:85)
    Et enfin, dans mon GtkTreeView je n'ajoute volontairement pas la première colonne. C'est une colonne qui servirait à recueillir des informations mais que j'aimerais ne pas afficher. Le résultat est bien celui escompté mais Valgrind renvoie :
    ==2135== 376 (124 direct, 252 indirect) bytes in 1 blocks are definitely lost in loss record 3,992 of 4,171
    ==2135== at 0x4023F50: malloc (vg_replace_malloc.c:236)
    ==2135== by 0x484CED3: g_malloc (in /lib/libglib-2.0.so.0.2400.1)
    ==2135== by 0x4862AB8: g_slice_alloc (in /lib/libglib-2.0.so.0.2400.1)
    ==2135== by 0x4862DB4: g_slice_alloc0 (in /lib/libglib-2.0.so.0.2400.1)
    ==2135== by 0x47E45C6: g_type_create_instance (in /usr/lib/libgobject-2.0.so.0.2400.1)
    ==2135== by 0x47C8907: ??? (in /usr/lib/libgobject-2.0.so.0.2400.1)
    ==2135== by 0x47CA079: g_object_newv (in /usr/lib/libgobject-2.0.so.0.2400.1)
    ==2135== by 0x47CA937: g_object_new (in /usr/lib/libgobject-2.0.so.0.2400.1)
    ==2135== by 0x431CB06: gtk_tree_view_column_new (in /usr/lib/libgtk-x11-2.0.so.0.2000.1)
    ==2135== by 0x431CB23: gtk_tree_view_column_new_with_attributes (in /usr/lib/libgtk-x11-2.0.so.0.2000.1)
    ==2135== by 0x8048D43: create_treeview (main.c:27)
    ==2135== by 0x8048F72: create_window (main.c:75)
    ==2135== by 0x8048F9C: main (main.c:87)
    Quelle est mon erreur ?

    En résumé, quelles sont les choses mal écrites dans le code, est-ce que mon utilisation de Valgrind est bonne, comment éviter tous ces "faux positifs" ? J'ajoute que j'utilise la version 2.20 de Gtk sur Debian si jamais ça avait une quelconque importance.

    Merci beaucoup pour votre aide et les connaissances que vous partagez.

  2. #2
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2009
    Messages
    1 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 395
    Points : 2 002
    Points
    2 002
    Par défaut
    Bonjour,
    je n'ai jamais utilisé Valgrind, mais les instructions pour l'utiliser sur des applications GTK+ sont là:
    http://live.gnome.org/Valgrind

    Pour ce qui est de ton style de programmation, il y a effectivement des fuites faciles à repérer dans ton code:

    Dans main: la variable window n'est pas libéré avant de quitter le programme.
    Dans create_windows: la variable builder n'est pas libérée avant de quitter la fonction appelante. Valgrind te l'indique clairement d'ailleurs. Comme il n'existe pas de fonction gtk_builder_free, il faut regarder dans la classe mère, GObject. Pour libérer ton objet GtkBuilder, il faut donc appeler g_object_unref.

    Ensuite, le fait qu'il reste des allocations pango, etc. est à mon avis normal: si tu ne libères pas un objet, toutes les ressources qu'il a lui même alloué pour son utilisation sont aussi perdues, et parmi elles, il peut y avoir des ressources créées par pango.
    Documentation officielle GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels par l'exemple (platform-demos):
    GTK (tous langages)

  3. #3
    Membre actif Avatar de Gamall
    Profil pro
    Étudiant ENSEA
    Inscrit en
    Août 2009
    Messages
    252
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant ENSEA

    Informations forums :
    Inscription : Août 2009
    Messages : 252
    Points : 221
    Points
    221
    Par défaut
    Euh, t'es sûr, pour la variable window qui n'est pas détruite ? Parce que il me semble que lorsque le signal "destroy" est émis, la fenêtre est détruite, non ?

  4. #4
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2009
    Messages
    1 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 395
    Points : 2 002
    Points
    2 002
    Par défaut
    Signals that all holders of a reference to the GtkObject should release the reference that they hold. May result in finalization of the object if all references are released.
    Traduction:
    Signale que tous les possesseurs d'une référence vers un GtkObject devraient lâcher la référence qu'ils tiennent. Peut entraîner la finalisation (NDLA: destruction) de l'objet si toutes les références ont été relâchées.
    Une fonction gtk_window_new, ou tout autre dérivé de GObject, va automatiquement initialiser le compteur de référence à 1 pour indiquer que cet objet est utilisé par 1 bout de code. Quand ce bout de code ne l'utilise plus, il doit appeler g_object_unref pour libérer 1 référence. Si le compteur de références tombe à 0, l'objet est détruit. Si quelqu'un d'autre avait entre-temps appelé g_object_ref pour prendre une autre référence sur la GtkWindow, le compteur de références aurait été incrémenté, évitant la destruction.

    Comme l'objet est détruit quand tout le monde a relâché sa référence, et que tu ne libères pas la tienne (créée implicitement par GTK), tu as une fuite.
    Documentation officielle GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels par l'exemple (platform-demos):
    GTK (tous langages)

  5. #5
    Membre actif Avatar de Gamall
    Profil pro
    Étudiant ENSEA
    Inscrit en
    Août 2009
    Messages
    252
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant ENSEA

    Informations forums :
    Inscription : Août 2009
    Messages : 252
    Points : 221
    Points
    221
    Par défaut
    C'est bizarre, lors de l'émission du signal "destroy", dans tous les cas, le compteur de références sera au moins à 1, sinon, ça voudrait dire que l'objet n'existe pas et a été détruit.

    Et si on fait quelque chose du genre
    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
     
    int
    main (int    argc,
          char  *argv[])
    {
        GtkWidget *window;
     
        gtk_init (&argc, &argv);
     
        gtk_widget_show_all (window);
        g_signal_connect (window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
     
        gtk_widget_show (window);
     
        gtk_main ();
     
        return 0;
    }
    window ne serait jamais détruit, car lors de l'émission de "destroy" le nombre de références est à 1

  6. #6
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2009
    Messages
    1 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 395
    Points : 2 002
    Points
    2 002
    Par défaut
    Citation Envoyé par artificier59 Voir le message
    C'est bizarre, lors de l'émission du signal "destroy", dans tous les cas, le compteur de références sera au moins à 1, sinon, ça voudrait dire que l'objet n'existe pas et a été détruit.
    Justement non. Si j'ai bien saisi le fonctionnement:
    1. tu appelles g_object_unref sur un objet dont le compteur est à 1
    2. le compteur tombe à 0 → le destructeur est appelé
    3. le destructeur émet le signal destroy
    4. le signal destroy est traité
    5. à la fin du destructeur, toute la mémoire de l'objet est libérée.


    Plus d'infos ici:
    http://library.gnome.org/devel/gobje...ct-memory.html
    Documentation officielle GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels par l'exemple (platform-demos):
    GTK (tous langages)

Discussions similaires

  1. Détection de fuites mémoire avec Valgrind
    Par dj.motte dans le forum GTK+ avec C & C++
    Réponses: 25
    Dernier message: 22/11/2008, 08h49
  2. Fuite mémoire avec code externe
    Par samW7 dans le forum C++
    Réponses: 8
    Dernier message: 01/02/2008, 02h33
  3. [AJAX] Appolo 13 - Fuite mémoire avec XHR
    Par mecatroid dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 24/09/2007, 14h52
  4. Fuites mémoires avec Vector
    Par ..alex.. dans le forum SL & STL
    Réponses: 15
    Dernier message: 10/08/2006, 11h35
  5. Fuite mémoire avec valgrind
    Par franchouze dans le forum C++
    Réponses: 3
    Dernier message: 05/06/2006, 16h47

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