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 :

Références et destroy()


Sujet :

GTK+ avec C & C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Avatar de Claude URBAN
    Homme Profil pro
    Prendre le temps de vivre. . .
    Inscrit en
    Mai 2006
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Prendre le temps de vivre. . .

    Informations forums :
    Inscription : Mai 2006
    Messages : 274
    Par défaut Références et destroy()
    Bonjour,


    1/ Existe-t-il un moyen de connaître le nombre de références que possède un widget ?

    Et si oui, lequel ?


    2/ Existe-t-il aussi, un moyen pour vérifier que gtk_widget_destroy(pObjet) a correctement effectué son travail ?

    Et si oui, quel est-il ?

    Autre que "Valgrind" ou système mémoire équivalent.


    La raison de ces deux questions est fort simple:

    Quand je fait un gtk_widget_destroy(pObjet), qu'est ce qui me prouve que la mémoire à correctement été nettoyée.

    Et qu'il ne reste pas un petit bout de quelque chose quelque part... d'où fuites mémoire.


    D'avance merci pour toutes les réponses que vous pourrez me fournir.

    Claude.

  2. #2
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par Claude URBAN Voir le message
    Bonjour,
    Bonjour

    Citation Envoyé par Claude URBAN Voir le message
    1/ Existe-t-il un moyen de connaître le nombre de références que possède un widget ?

    Et si oui, lequel ?
    Non il n'en existe pas. Du moins mis à disposition de la team Gtk+. Après, n'oublions pas que Gtk+ est écrit en C. La variable qui détient cette information reste accessible.

    Je répondrais donc aussi oui à la question. Pour être plus précis voila le cœur caché d'un GObject :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /**
     * GObject:
     * 
     * All the fields in the GObject structure are private 
     * to the #GObject implementation and should never be accessed directly.
     */
    struct  _GObject
    {
      GTypeInstance  g_type_instance;
     
      /*< private >*/
      volatile guint ref_count;
      GData         *qdata;
    };
    La variable ref_count devrait répondre à tes questionnements, mais il est très important de garder en tête qu'en temps normal on n'a pas à y accéder.

    Citation Envoyé par Claude URBAN Voir le message
    2/ Existe-t-il aussi, un moyen pour vérifier que gtk_widget_destroy(pObjet) a correctement effectué son travail ?

    Et si oui, quel est-il ?

    Autre que "Valgrind" ou système mémoire équivalent.
    À priori je réponds aussi non à cette deuxième question, d'autant qu'il pourrait y avoir des "mémoires cachées".

    Citation Envoyé par Claude URBAN Voir le message
    La raison de ces deux questions est fort simple:

    Quand je fait un gtk_widget_destroy(pObjet), qu'est ce qui me prouve que la mémoire à correctement été nettoyée.

    Et qu'il ne reste pas un petit bout de quelque chose quelque part... d'où fuites mémoire.
    Justement j'y viens. Quand j'écris "mémoire cachée" il faut se rappeler qu'un GObject peut emporter avec lui une donnée personnelle qu'on lui aurait attaché. Les fonctions utilisées sont g_object_set_data(); et g_object_get_data();. Cette donnée personnelle peut être longue comme le bras . Je suis loin d'être sûr que ces données soient libérées lorsque la référence tombe à 0.

    Finalement, la problématique est toujours la même lorsqu'on fait du C. Toujours être mettre de ses propres pointeurs et allocations mémoires. Pour ceux gérés par les autres, il va falloir leur faire confiance .

  3. #3
    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
    Bonjour Claude,

    Citation Envoyé par Claude URBAN Voir le message
    1/ Existe-t-il un moyen de connaître le nombre de références que possède un widget ?
    Même réponse que gérald, c'est la variable ref_count du GObject qui te permet d'accéder au compteur.

    Citation Envoyé par Claude URBAN Voir le message
    2/ Existe-t-il aussi, un moyen pour vérifier que gtk_widget_destroy(pObjet) a correctement effectué son travail ?

    Et si oui, quel est-il ?

    Autre que "Valgrind" ou système mémoire équivalent.
    Si tu as une glib compilée en mode debug, tu peux explorer le code par toi même:

    gtk_widget_destroy:
    https://git.gnome.org/browse/gtk+/tr...widget.c#n4686

    qui appelle g_object_run_dispose:
    https://git.gnome.org/browse/glib/tr...object.c#n3035

    Ce dernier prend une référence pour indiquer qu'il va utiliser l'objet, indique à tous les autres objets de relâcher la leur, puis appelle g_object unref pour lacher la prise juste avant référence, qui est la dernière. L'objet est alors détruit. Il existe quelques outils si tu veux suivre un peu plus facilement le cycle de vie des objets, mais je t'avoue ne jamais les avoir utilisés.

    Avec un débogueur tu peux capter les appels qui ajoutent/suppriment une référence à un objet, c'est la méthode exposée dans la doc officielle:
    https://developer.gnome.org/gobject/...ols-refdb.html

    Tu as aussi refdbg, qui semble encore d'actualité, ou gobject-list.

    Voir ces articles sur le même sujet (en anglais, désolé):
    https://blogs.gnome.org/danni/2011/0...ebugging-tool/
    http://www.burtonini.com/blog/2005/06/29/
    http://blog.desmottes.be/?post/2015/...-GstMiniObject


    Citation Envoyé par Claude URBAN Voir le message
    La raison de ces deux questions est fort simple:

    Quand je fait un gtk_widget_destroy(pObjet), qu'est ce qui me prouve que la mémoire à correctement été nettoyée.

    Et qu'il ne reste pas un petit bout de quelque chose quelque part... d'où fuites mémoire.
    Si tu ne fais pas un minimum confiance à une bibliothèque, ne l'utilise pas :p. Et pour savoir si tu peux lui faire confiance, lis le code, ou fais un exemple de base, et passe le dans Valgrind. Tu as des trucs sur l'utilisation de Valgrind avec GTK:
    https://wiki.gnome.org/Valgrind

  4. #4
    Membre éclairé
    Avatar de Claude URBAN
    Homme Profil pro
    Prendre le temps de vivre. . .
    Inscrit en
    Mai 2006
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Prendre le temps de vivre. . .

    Informations forums :
    Inscription : Mai 2006
    Messages : 274
    Par défaut
    Bonjour,

    Tout d'abord un grand merci à vous deux pour vos réponses.

    Je vais lire tout ça avec beaucoup d'attention et ne manquerai pas de revenir vers vous si je me pose d'autres questions.

    Mais en attendant:

    @gerald3d.

    Je m'intérroge sur ton commentaire suivant:

    Je suis loin d'être sûr que ces données soient libérées lorsque la référence tombe à 0.
    En fait, je m'étonne, car si j'ai bien compris le fonctionnement de la mémoire sous GTK+, c'est justement le but principal des compteurs de références que de permettre la suppression des widgets lorsque le dit compteur est égal à 0 et uniquement lorsqu'il est égal à 0.

    Lorsqu'un widget est créé ( et cela dépend, s'il descend de GObject ou de GInitiallyUnowned... la façon de procéder étant quelque peu différente) son compteur est incrémenté de +1.
    Chaque fois qu'il change d'utilisateur (ou de propriétaire) son compteur est également incrémenté de +1.
    C'est lorsqu'il quitte un utilisateur (ou propriétaire) qu'il sera décrémenté de -1.
    Et c'est UNIQUEMENT lorsque le compteur sera égal à 0 et seulement à partir de ce moment là que le widget pourra être détruit.
    Cela spécifiant explicitement qu'il ne reste plus aucun utilisateur (ou propriétaire) accroché à ce widget.

    Mais, on parle bien évidement des widgets et non des autres variables qui pourraient bien évidemment subsister.

    Donc...



    @liberforce.

    Si tu ne fais pas un minimum confiance à une bibliothèque, ne l'utilise pas...
    Ce n'est pas un manque de confiance, mais j'essaie autant que faire ce peu, de comprendre le fonctionnement de la gestion de la mémoire en GTK+... et c'est loin d'être simple et évident.

    J'ai découvert il y a peu, une note écrite par un professeur d'université de New York relatif justement à la gestion de la mémoire sous GTK+.
    Pour ceux que ça intéresse l'adresse de la note est ICI et l'adresse du site du professeur ICI.

    Document très très intéressant, mais en langue anglaise (bien évidement) et je m'efforce pour le moment de le traduire le plus correctement possible et surtout de comprendre ce que je traduis...

    D'où beaucoup de questions.

    Entre autres celle-ci, pour laquelle je n'arrive pas à trouver de réponse.

    Extrait de la documentation officielle GTK+ au paragraphe gtk_widget_destroy().

    In most cases, only toplevel widgets (windows) require explicit destruction, because when you destroy a toplevel its children will be destroyed as well.
    Que j'ai traduit de la façon suivante:
    Par contre, dans la plupart des cas, seuls les widgets "toplevel" (autrement dit les fenêtres principales) exigeront la destruction explicite, entraînant automatiquement celle de ses enfants.

    Ce qui semble être simple... sauf que dans TOUS les exemples que j'ai pu trouver sur le net, aucun ne termine le programme en détruisant correctement la fenêtre toplevel.

    Or il me semble, si je comprends bien ce texte, qu'il faudrait faire:

    gtk_widget_destroy(pWindow); // destruction de l'allocation mémoire.

    avant de faire:

    gtk_main_quit(); // fin de la boucle événementielle.

    Sachant que gtk_widget_destroy(pWindow) lance automatiquement un g_object_unref() et que c'est lorsque le compteur de références sera retombé à 0 que la fenêtre pourra être correctement détruite.

    Et je n'ai trouvé nul part spécifié que gtk_main_quit() appellait gtk_widget_destroy() ou un unref quelconque.

    Mais peut être ai-je mal compris ce texte ou bien mal traduit... ce qui d'ailleurs reviendrait au même.

    Merci de bien vouloir éclairer ma lanterne.

    Sur ce, @++ et bonne journée.


    Ah! une dernière chose, je ne vois pas comment utiliser ref_count.

    Claude.

  5. #5
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par Claude URBAN Voir le message
    Bonjour,

    Tout d'abord un grand merci à vous deux pour vos réponses.

    Je vais lire tout ça avec beaucoup d'attention et ne manquerai pas de revenir vers vous si je me pose d'autres questions.

    Mais en attendant:

    @gerald3d.

    Je m'intérroge sur ton commentaire suivant:



    En fait, je m'étonne, car si j'ai bien compris le fonctionnement de la mémoire sous GTK+, c'est justement le but principal des compteurs de références que de permettre la suppression des widgets lorsque le dit compteur est égal à 0 et uniquement lorsqu'il est égal à 0.

    Lorsqu'un widget est créé ( et cela dépend, s'il descend de GObject ou de GInitiallyUnowned... la façon de procéder étant quelque peu différente) son compteur est incrémenté de +1.
    Chaque fois qu'il change d'utilisateur (ou de propriétaire) son compteur est également incrémenté de +1.
    C'est lorsqu'il quitte un utilisateur (ou propriétaire) qu'il sera décrémenté de -1.
    Et c'est UNIQUEMENT lorsque le compteur sera égal à 0 et seulement à partir de ce moment là que le widget pourra être détruit.
    Cela spécifiant explicitement qu'il ne reste plus aucun utilisateur (ou propriétaire) accroché à ce widget.

    Mais, on parle bien évidement des widgets et non des autres variables qui pourraient bien évidemment subsister.

    Donc...
    Je ne parlais pas du GObject (ou du GtkWidget qui en dérive) mais des données personnelles que tu aurais pu y attacher. Je suis tout à fait d'accord avec toi quant à la gestion de la mémoire liée au compteur rf_count.

  6. #6
    Membre éclairé
    Avatar de Claude URBAN
    Homme Profil pro
    Prendre le temps de vivre. . .
    Inscrit en
    Mai 2006
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Prendre le temps de vivre. . .

    Informations forums :
    Inscription : Mai 2006
    Messages : 274
    Par défaut
    Bonjour,

    Ça y est, j'ai trouvé comment utiliser ref_count:

    Voici le résultat pour ceux que ça intéresse.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     
    printf("Compteur de références de pWidget: %d\n", G_OBJECT(pWidget) -> ref_count);
    Merci et bonne journée.

    Claude

  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 Claude URBAN Voir le message
    J'ai découvert il y a peu, une note écrite par un professeur d'université de New York relatif justement à la gestion de la mémoire sous GTK+.
    Pour ceux que ça intéresse l'adresse de la note est ICI et l'adresse du site du professeur ICI.

    Document très très intéressant, mais en langue anglaise (bien évidement) et je m'efforce pour le moment de le traduire le plus correctement possible et surtout de comprendre ce que je traduis...
    Intéressant, bien qu'un peu vieux. Il est fait mention de GtkObject qui n'existe plus en GTK3, et qui a été déprécié il y a longtemps dans GTK2. Mais à part ça le reste me semble toujours d'actualité.

    Citation Envoyé par Claude URBAN Voir le message
    Extrait de la documentation officielle GTK+ au paragraphe gtk_widget_destroy().

    Que j'ai traduit de la façon suivante:
    Par contre, dans la plupart des cas, seuls les widgets "toplevel" (autrement dit les fenêtres principales) exigeront la destruction explicite, entraînant automatiquement celle de ses enfants.

    Ce qui semble être simple... sauf que dans TOUS les exemples que j'ai pu trouver sur le net, aucun ne termine le programme en détruisant correctement la fenêtre toplevel.

    Or il me semble, si je comprends bien ce texte, qu'il faudrait faire:

    gtk_widget_destroy(pWindow); // destruction de l'allocation mémoire.

    avant de faire:

    gtk_main_quit(); // fin de la boucle événementielle.

    Sachant que gtk_widget_destroy(pWindow) lance automatiquement un g_object_unref() et que c'est lorsque le compteur de références sera retombé à 0 que la fenêtre pourra être correctement détruite.

    Et je n'ai trouvé nul part spécifié que gtk_main_quit() appellait gtk_widget_destroy() ou un unref quelconque.
    Comme je te l'ai dit peu de gens détruisent explicitement la mémoire à la fin d'un programme, parce que c'est comme dans la vraie vie. Si tu dis aux gens que quelqu'un d'autre passera faire le ménage à leur place (en l'occurrence, le système d'exploitation), ils se mettent à jeter sans nettoyer eux même. Si tu ne fais pas des tonnes d'allocations/désallocations, tu n'as pas vraiment de sources de fuite mémoire, et donc pas vraiment de raisons de lancer Valgrind. Le fait de ne pas détruire cette fenêtre toi même est donc sans aucun impact. C'est mieux de la détruire (parce que ça fait ça de moins à rajouter si toi ou quelqu'un d'autre veut lancer Valgrind sur ton programme), mais globalement on s'en fout un peut que tu ramasses tous tes déchets ou pas quand de toute façon dans la miliseconde la benne à ordures va passer et tout embarquer.

    Cette fenêtre que tu veux détruire, elle a la même durée de vie que ton programme. Ce n'est pas elle qui sera à l'origine d'une fuite. Une fuite de mémoire c'est quand tu fais des allocations pendant l'exécution de ton programme, que tu n'as besoin de cette mémoire que temporairement (pour faire un calcul par exemple), mais qu'une fois que tu n'en as plus besoin, tu ne libères pas cette mémoire. Ça c'est une fuite, parce que tout le temps que ton programme continue à tourner, il utilise plus de mémoire que nécessaire. Si tu répètes plusieurs fois cette opération, tu peux te retrouver à consommer beaucoup de mémoire, voire toute la mémoire et provoquer une exception bas niveau OOM (Out-Of-Memory). Et là, l'OS est sans pitié, si tu ne te comportes pas bien et abuses des ressources, tu gicles:

    Nom : 1280px-Out_of_Memory_in_Linux.jpg
Affichages : 84
Taille : 274,9 Ko

    Donc arrête de te torturer pour une malheureuse fenêtre. Au moment où tu veux la détruire, elle n'en a de toute façon plus pour longtemps.

    Ensuite, non, gtk_main_quit ne détruira pas tes fenêtres à ta place. Il ne détruira que les ressources qu'il a lui même créées (comme la main loop, la boucle d'événements de la GLib).
    C'est affectivement à toi de les détruires... ou de laisser cette tâche à l'OS.

    Citation Envoyé par Claude URBAN Voir le message
    Ah! une dernière chose, je ne vois pas comment utiliser ref_count.
    En ce qui concerne le compteur de références, à priori un truc de ce genre devrait suffire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    GtkWidget *button = gtk_button_new();
    // utilisation de ce widget, ajout dans un conteneur, etc.
    printf("%s\n", G_OBJECT(button)->ref_count);

  8. #8
    Membre éclairé
    Avatar de Claude URBAN
    Homme Profil pro
    Prendre le temps de vivre. . .
    Inscrit en
    Mai 2006
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Prendre le temps de vivre. . .

    Informations forums :
    Inscription : Mai 2006
    Messages : 274
    Par défaut
    Bonjour,


    Pour ceux que ça pourrait intéresser, je réponds ci-dessous aux deux questions que j’ai posées en tout début.

    Sans oublier de remercier au passage tous ceux qui m’ont fourni les informations nécessaires et indispensables : MERCI.

    1/ Existe-t-il un moyen de connaître le nombre de références que possède un widget ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    printf (" Référence du widget Nom_du_widget : %d\n", G_OBJECT(pNom_du_widget)->ref_count) ;
    2/ Existe-t-il aussi, un moyen pour vérifier que gtk_widget_destroy(pObjet) a correctement effectué son travail ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    printf (" Nom de l’instance : %s\n", g_type_name_from_instance ((GTypeInstance *) pNom_du_widget)) ;
    Si le widget existe, le Nom de l’instance sera : GtkNom_du_widget.
    Si le widget n’existe plus, le Nom de l’instance sera égal à <NULL-class>.
    Si entre temps, le pointeur a été ré-initialisé à NULL, alors le Nom de l’instance sera égal à <NULL-instance>.

    Une référence égale à 0, plus une instance égale à <NULL-class>, devraient permettre au programmeur de s'assurer que le travail a été correctement effectué.

    Je clos donc ce sujet.

    Voilà, et encore merci à vous tous.

    Claude

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

Discussions similaires

  1. [Livres/Références] Vos avis..
    Par Community Management dans le forum Livres
    Réponses: 6
    Dernier message: 25/07/2005, 19h31
  2. Références / tutoriels MFC COM
    Par DivisionParZéro dans le forum MFC
    Réponses: 3
    Dernier message: 03/02/2004, 17h49
  3. Passage d'un tableau par référence?
    Par sebduth dans le forum C
    Réponses: 9
    Dernier message: 16/07/2003, 18h32
  4. [Concept] Table de référence
    Par matlo dans le forum Décisions SGBD
    Réponses: 3
    Dernier message: 20/01/2003, 15h01

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