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 :

gestion mémoire (valgrind, g_mem_profile, wrapping malloc)


Sujet :

GTK+ avec C & C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Août 2009
    Messages
    65
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 65
    Par défaut gestion mémoire (valgrind, g_mem_profile, wrapping malloc)
    Bonjour,

    Je poursuis mon apprentissage de la Glib, du GTK+ conjointement à ma redécouverte du C après abandon de plusieurs années.

    N'êtant pas encore très sûr de moi dans ma gestion de la mémoire, je cherche un moyen sûr et imparable si possible de faire les vérifications nécessaires.

    J'étudie 3 pistes différentes:

    * wrapper malloc, g_malloc, free, g_free, ... à coup de directives préprocesseur.
    * valgrind qui semble profondément troublé par Glib et GTK
    * utilisation de g_mem_profile (avec at_exit)

    ------------------------------------

    Voici le code d'un programme bidon (une gtk_window, une gtk_hbox et 2 boutons) pour illustrer:

    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
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    #include <stdlib.h>
    #include <gtk/gtk.h>
     
     
    #define DEBUG_MEM_PROFILE
    #define DEBUG_MALLOC
     
    #ifdef DEBUG_MALLOC
    	/* wrapping de malloc, free etc */
    int COMPTEUR_MALLOC = 0;
     
    void *debug_malloc (char *File, int Line, size_t Size) 
    {
    	void *allocation;
    	allocation = g_malloc(Size) ;
    	fprintf(stderr, "Allocation n° %d en %p in file %s, line %d : %d bytes.\n", COMPTEUR_MALLOC++, allocation, File, Line, Size);
    	return allocation;
    }
     
    void debug_free (char *File, int Line, void *allocation) 
    {
    	fprintf(stderr, "Libération n° %d en %p in file %s, line %d\n", --COMPTEUR_MALLOC, allocation, File, Line);
    	g_free(allocation);
    }
     
    #define malloc(Size) debug_malloc(__FILE__,__LINE__,Size)
    #define g_malloc(Size) debug_malloc(__FILE__,__LINE__,Size)
    #define free(Pointer) debug_free(__FILE__,__LINE__,Pointer)
    #define g_free(Pointer) debug_free(__FILE__,__LINE__,Pointer)
     
    #endif
     
    #ifdef DEBUG_MEM_PROFILE
    	/* appel de g_mem_profile par atexit */
    void sortie (void)
    {	g_mem_profile();
    }
    #endif
     
     
     
     
    void cb_quit (GtkWidget *, gpointer);
    void cb_unsensitive (GtkWidget *p_widget, gpointer user_data);
     
    int main (int argc, char **argv)
    {
    #ifdef DEBUG_MEM_PROFILE
    	/* déclaration exigée par g_mem_profile ? (voir doc) */
    	extern GMemVTable *glib_mem_profiler_table;
    #endif
     
    	GtkWidget *p_window = NULL;
    	GtkWidget *p_main_box = NULL;
    	GtkButton *p_button[2] = {NULL, NULL};
     
    #ifdef DEBUG_MEM_PROFILE
    	/* sortie pour debug (g_mem_profile) */
    	atexit(sortie);
    	/* setting exigé par g_mem_profile ? (voir doc) */
    	g_mem_set_vtable (glib_mem_profiler_table);
    #endif
     
    	/* Initialisation de GTK+ */
    	gtk_init (&argc, &argv);
     
    	/* Creation de la fenetre principale de notre application */
    	p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    	g_signal_connect (G_OBJECT (p_window), "destroy", G_CALLBACK (cb_quit), NULL);
     
    	/* Creation du conteneur principal */
    	p_main_box = gtk_hbox_new (FALSE, 0);
    	gtk_container_add (GTK_CONTAINER (p_window), p_main_box);
     
    	/* Creation des boutons */
    	{
    		p_button[0] = (GtkButton *) gtk_button_new_from_stock (GTK_STOCK_QUIT);
    		g_signal_connect (G_OBJECT (p_button[0]), "clicked", G_CALLBACK (cb_quit), NULL);
    		gtk_box_pack_start (GTK_BOX (p_main_box), GTK_WIDGET (p_button[0]), FALSE, FALSE, 5);
     
    		p_button[1] = (GtkButton *) gtk_button_new_with_label ("NADA");
    		g_signal_connect (G_OBJECT (p_button[1]), "clicked", G_CALLBACK (cb_unsensitive), p_button[1]);
    		gtk_box_pack_start (GTK_BOX (p_main_box), GTK_WIDGET (p_button[1]), FALSE, FALSE, 5);
     
     
     
    	}
     
    	/* Affichage de la fenetre principale */
    	gtk_widget_show_all (p_window);
     
    	/* Lancement de la boucle principale */
    	gtk_main ();
     
    	return EXIT_SUCCESS;
    }
     
    void cb_quit (GtkWidget *p_widget, gpointer user_data)
    {
    	gtk_main_quit();
     
    	/* Parametres inutilises */
    	(void)p_widget;
    	(void)user_data;
    }
     
    void cb_unsensitive (GtkWidget *p_widget, gpointer user_data)
    {
    	gtk_widget_set_sensitive (GTK_WIDGET (p_widget), ! GTK_WIDGET_IS_SENSITIVE(p_widget));
     
    	/* Parametres inutilises */
    	(void)user_data;
    }
    ------------------------------------
    MES QUESTIONS:

    1/ des remarques et commentaires éventuels sur mon code C (c'est toujours utile) ?

    2/ Méthode avec valgrind

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    ==32562== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 85 from 1)
    ==32562== malloc/free: in use at exit: 2,435,950 bytes in 14,945 blocks.
    ==32562== malloc/free: 56,739 allocs, 41,794 frees, 6,028,796 bytes allocated.
    ==32562== For counts of detected errors, rerun with: -v
    ==32562== searching for pointers to 14,945 not-freed blocks.
    ==32562== checked 2,587,248 bytes.
    ==32562==
    ==32562== LEAK SUMMARY:
    ==32562==    definitely lost: 49,222 bytes in 1,759 blocks.
    ==32562==      possibly lost: 82,920 bytes in 91 blocks.
    ==32562==    still reachable: 2,303,808 bytes in 13,095 blocks.
    ==32562==         suppressed: 0 bytes in 0 blocks.
    Valgrind me sort des fuites-mémoires

    a/ je ne peux pas différencier les allocations/désallocations imputables à la g_lib des miennes propres. Donc valgrind inutilisable ? Comment faites-vous ?

    b/ Que représentent les "still reachable" (d'une façon générale hors du contexte glib/gtk) ? Est-ce que ça peut induire un souci de sécurité ?


    3/ Méthode avec g_mem_profile

    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
    GLib Memory statistics (successful operations):
     blocks of | allocated  | freed      | allocated  | freed      | n_bytes
      n_bytes  | n_times by | n_times by | n_times by | n_times by | remaining
               | malloc()   | free()     | realloc()  | realloc()  |
    ===========|============|============|============|============|===========
             1 |        120 |        116 |          0 |          0 |         +4
             2 |        139 |         73 |          0 |          0 |       +132
    ...
          2012 |          0 |          0 |          1 |          1 |         +0
          2024 |          0 |          0 |          1 |          1 |         +0
          2036 |          0 |          0 |          1 |          1 |         +0
          2040 |          1 |          0 |          0 |          0 |      +2040
          2048 |          3 |          3 |          7 |          4 |      +6144
          2228 |          1 |          0 |          0 |          0 |      +2228
          4001 |          1 |          1 |          0 |          0 |         +0
       >  4096 |          6 |          5 |          5 |          1 |        ***
    GLib Memory statistics (failing operations):
     --- none ---
    Total bytes: allocated=789829, zero-initialized=85278 (10,80%), freed=551680 (69,85%), remaining=238149
    a/ utilisation correcte ?
    Je ne suis pas sûr d'avoir bien compris la doc même si ça semble fonctionner.

    b/ interprétation:
    Là aussi, tout n'est pourtant pas libéré par le GTK ? freed=551680 (69,85%), remaining=238149
    (Et les chiffres sont totalement différents de valgrind, ce qui n'est pas forcément étonnant)

    4/ Méthode avec wrapping malloc
    La méthode est plutôt sympa même si je ne l'ai pas implémentée jusqu'au bout (notamment les realloc).
    L'inconvénient majeur est que certaines fonctions de la g_lib comme g_strdup par exemple exigent un free explicite sans malloc préalable ce qui fausse mes résultats. (trop de free et pas assez de malloc)
    Mais au moins je pense que je peux checker assez bien quand même mes propres allocations et désallocations par ce biais. Des commentaires ?

  2. #2
    Membre Expert
    Homme Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 259
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 259
    Par défaut
    Valgrind avec la glib, ça s'utilise plutôt bien. Il y a quelques faux positifs causés par la glib, mais tu apprends vite à les reconnaître. Il faut lancer valgrind avec G_SLICE=always-malloc dans ton environnement par contre. Les "still reachable", c'est des zones mémoires allouées sur lesquelles tu as encore un pointeur quand ton programme quitte. Dans l'absolu, ça n'est pas gênant, mais ça peut parfois indiquer des pbs de leaks (par exemple un cache dans lequel tu insères plein plein déléments sans jamais le vider).

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Août 2009
    Messages
    65
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 65
    Par défaut
    @Teuf13,

    J'ai fait un export G_SLICE=always-malloc au préalable et après la boucle gtk_main, j'ai réinitialisé à NULL mes 4 widgets:
    p_window = NULL;
    p_main_box = NULL;
    p_button[0] = NULL;
    p_button[1] = NULL;

    J'obtiens toujours:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ==3302== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 85 from 1)
    ==3302== malloc/free: in use at exit: 2,316,182 bytes in 19,242 blocks.
    ==3302== malloc/free: 71,608 allocs, 52,366 frees, 6,054,229 bytes allocated.
    ==3302== For counts of detected errors, rerun with: -v
    ==3302== searching for pointers to 19,242 not-freed blocks.
    ==3302== checked 2,528,856 bytes.
    ==3302==
    ==3302== LEAK SUMMARY:
    ==3302==    definitely lost: 49,222 bytes in 1,759 blocks.
    ==3302==      possibly lost: 800 bytes in 20 blocks.
    ==3302==    still reachable: 2,266,160 bytes in 17,463 blocks.
    ==3302==         suppressed: 0 bytes in 0 blocks.

  4. #4
    Rédacteur

    Avatar de gege2061
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2004
    Messages
    5 840
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Juin 2004
    Messages : 5 840
    Par défaut
    Citation Envoyé par vitoubien Voir le message
    @Teuf13,

    J'ai fait un export G_SLICE=always-malloc au préalable et après la boucle gtk_main, j'ai réinitialisé à NULL mes 4 widgets:
    p_window = NULL;
    p_main_box = NULL;
    p_button[0] = NULL;
    p_button[1] = NULL;
    Essaye d'utiliser g_object_unref

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Août 2009
    Messages
    65
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 65
    Par défaut
    @Gege,

    j'ai donc remplacé mes réinitialisations à NULL par seulement
    g_object_unref(p_window); dans un premier temps et en compilant sans aucune de mes options de débogage.

    Et ça me génère toutes ces erreurs:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    (g_mem_profile:9652): Gtk-CRITICAL **: gtk_main_quit: assertion `main_loops != NULL' failed
     
    (g_mem_profile:9652): GLib-GObject-WARNING **: instance with invalid (NULL) class pointer
     
    (g_mem_profile:9652): GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed
     
    (g_mem_profile:9652): GLib-GObject-WARNING **: instance with invalid (NULL) class pointer
     
    (g_mem_profile:9652): GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed
    Et si je rajoute:

    g_object_unref(p_button[1]);
    g_object_unref(p_button[0]);
    g_object_unref(p_main_box);
    g_object_unref(p_window);

    Alors là c'est pire encore.

    Cette erreur "(g_mem_profile:9652): Gtk-CRITICAL **: gtk_main_quit: assertion `main_loops != NULL' failed" me parait particulièrement bizarre alors que je ne suis même plus dans la boucle gtk_main !

  6. #6
    Membre Expert
    Homme Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 259
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 259
    Par défaut
    Comme dit, il y a quelques faux posifits avec valgrind + gtk+ Mais dans ton exemple, c'est surtout l'utilisation de GMemProfile avec valgrind qui a l'air de mettre un peu le bazar

  7. #7
    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
    Par défaut
    Citation Envoyé par vitoubien Voir le message
    @Gege,

    j'ai donc remplacé mes réinitialisations à NULL par seulement
    g_object_unref(p_window); dans un premier temps et en compilant sans aucune de mes options de débogage.

    Et ça me génère toutes ces erreurs:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    (g_mem_profile:9652): Gtk-CRITICAL **: gtk_main_quit: assertion `main_loops != NULL' failed
     
    (g_mem_profile:9652): GLib-GObject-WARNING **: instance with invalid (NULL) class pointer
     
    (g_mem_profile:9652): GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed
     
    (g_mem_profile:9652): GLib-GObject-WARNING **: instance with invalid (NULL) class pointer
     
    (g_mem_profile:9652): GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed
    Et si je rajoute:

    g_object_unref(p_button[1]);
    g_object_unref(p_button[0]);
    g_object_unref(p_main_box);
    g_object_unref(p_window);

    Alors là c'est pire encore.

    Cette erreur "(g_mem_profile:9652): Gtk-CRITICAL **: gtk_main_quit: assertion `main_loops != NULL' failed" me parait particulièrement bizarre alors que je ne suis même plus dans la boucle gtk_main !
    Tu peux nous redonner le code complet qui provoque ces erreurs ?

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. gestion mémoire sur plusieurs malloc
    Par contremaitre dans le forum C
    Réponses: 39
    Dernier message: 27/03/2008, 13h51
  2. TAO, Value types et gestion mémoire
    Par TiChabin972 dans le forum CORBA
    Réponses: 1
    Dernier message: 25/04/2006, 20h55
  3. [D7] Tableau dynamique et Gestion mémoire
    Par Cl@udius dans le forum Langage
    Réponses: 7
    Dernier message: 13/03/2006, 15h16
  4. [Gestion mémoire] SetLength sur TDoubleDynArray
    Par MD Software dans le forum Langage
    Réponses: 14
    Dernier message: 24/04/2005, 21h11
  5. Gestion mémoire des Meshes (LPD3DXMESH)
    Par [Hideki] dans le forum DirectX
    Réponses: 1
    Dernier message: 08/07/2003, 20h34

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