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++

  1. #1
    Membre du Club
    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
    Points : 53
    Points
    53
    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 expérimenté
    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
    Points : 1 633
    Points
    1 633
    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 du Club
    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
    Points : 53
    Points
    53
    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 : 40
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2004
    Messages : 5 840
    Points : 11 625
    Points
    11 625
    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 du Club
    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
    Points : 53
    Points
    53
    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 expérimenté
    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
    Points : 1 633
    Points
    1 633
    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
    Membre du Club
    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
    Points : 53
    Points
    53
    Par défaut
    @Teuf,
    J'ai fait plusieurs tests en désactivant ou non g_mem_profile.

    Bon je crois que je pourrai pas faire mieux.

    Merci pour vos réponses.
    Bonne nuit et bonne semaine.

  8. #8
    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 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 ?
    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)

  9. #9
    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
    Pour l'utilisation de Valgrind, tu as des infos ici:
    http://live.gnome.org/libchamplain/c...7ca91007025cd6
    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)

  10. #10
    Membre du Club
    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
    Points : 53
    Points
    53
    Par défaut
    Hello,
    le code complet:


    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
    114
    115
    116
    117
    118
    119
     
    #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 ();
     
    	g_object_unref(p_button[1]);
    	g_object_unref(p_button[0]);
    	g_object_unref(p_main_box);
    	g_object_unref(p_window);
     
    	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;
    }
    Et les erreurs générées:

    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
     
    (g_mem_profile:8223): GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)'
     
    (g_mem_profile:8223): GLib-GObject-CRITICAL **: g_signal_emit_valist: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed
     
    (g_mem_profile:8223): GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)'
     
    (g_mem_profile:8223): GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed
     
    (g_mem_profile:8223): GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)'
     
    (g_mem_profile:8223): GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed
     
    (g_mem_profile:8223): GLib-GObject-CRITICAL **: g_object_unref: assertion `G_IS_OBJECT (object)' failed
     
    (g_mem_profile:8223): GLib-GObject-WARNING **: gsignal.c:2133: signal id `7' is invalid for instance `0x806cab8'
     
    (g_mem_profile:8223): GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)'
     
    (g_mem_profile:8223): GLib-GObject-CRITICAL **: g_signal_emit_valist: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed
     
    (g_mem_profile:8223): GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)'
     
    (g_mem_profile:8223): GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed
     
    (g_mem_profile:8223): GLib-GObject-WARNING **: instance of invalid non-instantiatable type `(null)'
     
    (g_mem_profile:8223): GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed
     
    (g_mem_profile:8223): Gtk-CRITICAL **: gtk_main_quit: assertion `main_loops != NULL' failed
     
    (g_mem_profile:8223): GLib-GObject-WARNING **: instance with invalid (NULL) class pointer
     
    (g_mem_profile:8223): GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed
     
    (g_mem_profile:8223): GLib-GObject-WARNING **: instance with invalid (NULL) class pointer
     
    (g_mem_profile:8223): GLib-GObject-CRITICAL **: g_signal_handlers_destroy: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed

  11. #11
    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
    Après quelques tests, g_mem_profile m'a l'air un peu inutile... On dirait qu'il te donne les stats de la mémoire que GTK n'a pas libéré pour que l'OS le fasse, en plus de tes statistiques à toi. Résultat: impossible de différencier les deux. gtk_main_quit est censé détruire tous les widgets, mais même des exemples simplistes n'affichent pas à la fin du programme 100% de mémoire libérée...
    http://mail.gnome.org/archives/gtk-l.../msg00075.html

    Mieux vaut se tourner vers valgrind...
    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)

  12. #12
    Membre du Club
    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
    Points : 53
    Points
    53
    Par défaut
    Citation Envoyé par liberforce Voir le message
    Après quelques tests, g_mem_profile m'a l'air un peu inutile...

    Si si ! C'est l'usage que j'en faisais qui était inutile.

    En fait, cela sert à customiser malloc, realloc, free, etc

    De cette façon, par exemple j'obtiens une trace de toutes (?) les allocations, reallocations et libérations réalisées dans la Glib:

    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
    #include <stdlib.h>
    #include <gtk/gtk.h>
    #include <assert.h>
     
    int NB_ALLOC = 0;
     
    void sortie (void)
    {	g_mem_profile();
    }
     
    gpointer xmalloc (gsize size)
    {
    	gpointer p = malloc (size);
    	if (size)
    		assert (p != NULL);
    	fprintf(stderr, "ALLOCATION (n° %d) de %d en %p\n", NB_ALLOC++, size, p);
    	return p;
    }
     
    gpointer xrealloc (gpointer p, gsize size)
    {
    	gpointer g;
    	g = realloc (p, size);
    	if (size)
    		assert (g != NULL);
    	fprintf(stderr, "REALLOCATION %d de %p en %p\n", size, p, g);
    	return g;
    }
     
    void xfree (gpointer p)
    {
    	fprintf(stderr, "FREE (n° %d) de %p\n", --NB_ALLOC, p);
    	free (p);
    }
     
    void cb_quit (GtkWidget *, gpointer);
    void cb_unsensitive (GtkWidget *p_widget, gpointer user_data);
     
    int main (int argc, char **argv)
    {
     
    	GtkWidget *p_window = NULL;
    	GtkWidget *p_main_box = NULL;
    	GtkButton *p_button[2] = {NULL, NULL};
     
    	GMemVTable vtab = { xmalloc, xrealloc, xfree, NULL, NULL, NULL };
    	g_mem_set_vtable (&vtab);
     
    	/* sortie pour debug (g_mem_profile) */
    	atexit(sortie);
     
    	/* 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 ();
     
    /*	g_object_unref(p_button[1]);
    	g_object_unref(p_button[0]);
    	g_object_unref(p_main_box);
    	g_object_unref(p_window);
    */	
    	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;
    }
    Je me suis inspiré de ce qui est fait ici:
    http://www.google.fr/codesearch/p?hl...mem_set_vtable

    Question bête: pour afficher une gsize, on utilise le format %d ou autre ?

    Autre question: le xfree, c'est moi l'ai rajouté. Est-ce qu'il n'y aurait pas un assert à ajouter en cas de mauvais usage de free ? Lequel ?

    Essaye d'executer ce code, c'est amusant !!!

  13. #13
    Membre du Club
    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
    Points : 53
    Points
    53
    Par défaut
    Si je compte les malloc, realloc et free avec ce code:

    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
    int NB_ALLOC = 0;
    int NB_REALLOC = 0;
    int NB_FREE = 0;
     
    gpointer xmalloc (gsize size)
    {
    	gpointer p = malloc (size);
    	if (size)
    		assert (p != NULL);
    	fprintf(stderr, "ALLOCATION (n° %d) de %d en %p\n", NB_ALLOC++, size, p);
    	return p;
    }
     
    gpointer xrealloc (gpointer p, gsize size)
    {
    	gpointer g;
    	g = realloc (p, size);
    	if (size)
    		assert (g != NULL);
    	fprintf(stderr, "REALLOCATION (n° %d) %d de %p en %p\n", NB_REALLOC++, size, p, g);
    	return g;
    }
     
    void xfree (gpointer p)
    {
    	fprintf(stderr, "FREE (n° %d) de %p\n", NB_FREE++, p);
    	free (p);
    }
    G_SLICE=always-malloc G_DEBUG=gc-friendly valgrind --tool=memcheck ./g_mem_profile 1>log.txt 2>&1

    j'obtiens quand même des chiffres différents de ceux annoncés par valgrind. Il manque donc quelque chose dans ma logique.

    Par contre, le but est atteint, je peux maintenant différencier mes propres malloc de ceux de la Glib.
    Maintenant, est-ce que tout ça était vraiment utile, c'est une autre question !

  14. #14
    Membre expérimenté
    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
    Points : 1 633
    Points
    1 633
    Par défaut
    Citation Envoyé par vitoubien Voir le message
    Par contre, le but est atteint, je peux maintenant différencier mes propres malloc de ceux de la Glib.
    Je suis pas sûr pourquoi tu dis ça. Toutes les allocations faites par la glib passeront par ton allocateur (vu que la glib utilise aussi g_malloc/g_free). Par contre, les allocations faites par des fonctions qui n'utilisent pas g_malloc/g_free (par ex qui utilise directement malloc/free) ne seront pas comptabilisée par ton allocateur. Ca doit être ça la différence avec valgrind. Honnêtement, ça me paraît beaucoup plus efficace d'apprendre à reconnaître les 3/4 faux positifs ajoutés par la glib (voire d'écrire un fichier de suppression pour ces cas) plutôt que de traquer les allocations mémoires à la main.

  15. #15
    Membre du Club
    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
    Points : 53
    Points
    53
    Par défaut
    @Teuf,

    Oui tu as raison, je me suis laissé emporté par mon enthousiasme.

    Nbre total d'ALLOCATION 31952
    Nbre total de REALLOCATION 5736
    Nbre total de FREE 23455
    ==20806==
    ==20806== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 85 from 1)
    ==20806== malloc/free: in use at exit: 2,316,254 bytes in 19,245 blocks.
    ==20806== malloc/free: 73,033 allocs, 53,788 frees, 6,136,214 bytes allocated.

    Mais je ne comprends toujours pas bien d'où vient la différence. Tant pis.

  16. #16
    Membre expérimenté
    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
    Points : 1 633
    Points
    1 633
    Par défaut
    Comme dit, avec ton code, si tu appelles malloc/free directement (au lieu de g_malloc/g_free), l'allocation ne sera pas compatibilisée. La différence provient probablement de là.

  17. #17
    Membre du Club
    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
    Points : 53
    Points
    53
    Par défaut
    Oui si bien sûr.

    Bon tout cela était assez vain finalement.
    Je me demande pourquoi les développeurs de gxine utilisent ce mécanisme.

    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
    #ifndef GLIB_USES_SYSTEM_MALLOC
    #include <assert.h>
    gpointer xmalloc (gsize size)
    {
      gpointer p = malloc (size);
      if (size)
        assert (p != NULL);
      return p;
    }
     
    gpointer xrealloc (gpointer p, gsize size)
    {
      p = realloc (p, size);
      if (size)
        assert (p != NULL);
      return p;
    }
    #endif

  18. #18
    Membre expérimenté
    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
    Points : 1 633
    Points
    1 633
    Par défaut
    A priori pour tout arrêter si une allocation mémoire échoue.

+ 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