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
Valgrind me sort des fuites-mémoires
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.
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
a/ utilisation correcte ?
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
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 ?
Partager