1. #1
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    décembre 2012
    Messages
    47
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : décembre 2012
    Messages : 47
    Points : 39
    Points
    39

    Par défaut Exception "External: SigSegv" à la fermeture de l'application

    Bonjour.

    Je butte sur un dernier bug de l'application que je développe en ce moment. À la fermeture de l'application j'obtiens l'erreur
    Le projet monprojet a levé une classe d'exception "External: SIGSEGV" à l'adresse 40D898
    déboggeur actif on pas (lancé hors Lazarus on obtient un splendide plantage final ...).

    En cherchant pas à pas, l'erreur provient de TWin32WidgetSet.AppProcessMessages, DispatchMessageW(@AMessage) ligne 566.

    Note importante : l'appli crée des objets contenant pour certains d'autres objets que je pense avoir libérés en fermeture d'appli ; mais tant que je n'ai pas demandé à l'appli de les créer, elle se ferme sans erreur.

    D'où plusieurs questions :
    - cette erreur est-elle bien liée à un problème de libération de mémoire (sigsegv => a priori oui) ?

    - Free Pascal n'a pas un mécanisme de libération des objets créés (pour les oublis) ?

    - quand je libère un objet (.free) les objets qu'il contient sont-ils libérés aussi ? Je pense en particulier à mes objets mais aussi à ceux de composants de Lazarus (ex. TSQLite3Connexion et les Tdatabase, TTransaction, ...).

    - bon, j'avoue, je n'ai pas tenu proprement la liste de tous les trucs alloués à un moment donné ; y a-t-il moyen (simple ! ) d'en retrouver la liste ou la trace quelque part ?

    Merci

    PS : y a-t-il moyen de capturer cette exception puisqu'elle à lieu en dehors de TForm1.FormClose ?

  2. #2
    Membre expert
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mai 2002
    Messages
    2 504
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : mai 2002
    Messages : 2 504
    Points : 3 970
    Points
    3 970

    Par défaut

    salut

    je pense surtout que tu as des événements qui ne sont pas encore traités lors de la fermeture de ta fenêtre
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    décembre 2012
    Messages
    47
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : décembre 2012
    Messages : 47
    Points : 39
    Points
    39

    Par défaut

    Des événements de quel ordre ?

    J'ai noté qu'en fermant les autres fenêtres de saisie de valeurs, les routines liées à des modifications des champs de saisie étaient activés alors qu'aucune action n'étaient faites dessus. Pourrait-il y avoir de tels événements curieusement déclenchés à la fermeture ?



    Je viens de faire la chasse à tous les objets et les variables créées et l'erreur à toujours lieu. Parfois même explicitement libérer certains objets liés à mon objet principal provoque de nouvelles erreurs, apparemment sans raison.

    Exemple : j'ai des composants (mes objets principaux) qui peuvent avoir un label comme propriété. Une fois le label du premier composant supprimé, tous les autres génère une erreur alors qu'il s'agit bien de labels différents (on les voit à l'écran) ! Même en commençant par deux composants sans label, le troisième mais premier composant avec un label plante en voulant libérer celui-ci !

    Merci.

    PS
    Je viens de mettre des points d'arrêt dans toutes mes routines susceptibles d'être rappelées en fermeture (cf. la mise à jour et validation de TEdit) et en particulier dans les gestionnaires d'événement, et l'erreur se produit toujours sans passer par l'une de ces routines.
    Peut-être parce que l'objet qui la possède n'est plus instancié. En tout cas, impossible de cibler par ce moyen le fautif.

  4. #4
    Membre confirmé

    Homme Profil pro
    Autre
    Inscrit en
    novembre 2015
    Messages
    111
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : novembre 2015
    Messages : 111
    Points : 464
    Points
    464

    Par défaut

    Vous parlez de plusieurs types d'objet; il est donc difficile d'apporter une réponse précise.

    Ceci étant, en règle général, les objets de la LCL (exemple: un Label) n'ont pas à être libérés quant l'application se termine: même ceux créés dynamiquement. La LCL s'en chargera elle-même (sauf cas très particulier).

  5. #5
    Membre expert
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mai 2002
    Messages
    2 504
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : mai 2002
    Messages : 2 504
    Points : 3 970
    Points
    3 970

    Par défaut

    Salut

    Si tu as les sources de tes objets, regarde si dans le destructor il libère tous les objets créés par lui-même.

    Quand tu libères tes objet comment fais-tu ?
    Sont-ils dans une liste ?
    Ta database est créée dynamiquement ?
    As-tu inséré son instance dans le flux pour qu'elle soit libéré" automatiquement ?
    ....
    Tu vois j'ai des milliers de questions... Il est très difficile de te répondre, tout dépend de la construction de ton appli et comment tu as instancié les composants.
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  6. #6
    Membre confirmé

    Homme Profil pro
    Amateur Passionné
    Inscrit en
    septembre 2015
    Messages
    308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : septembre 2015
    Messages : 308
    Points : 636
    Points
    636

    Par défaut

    Salut

    cette erreur est-elle bien liée à un problème de libération de mémoire (sigsegv => a priori oui) ?
    En fait non SIGSEGV, elle le fait il semblerait plutôt qu'à la fermeture de ton programme tu accèdes à un objet ou un sous objet déjà libéré. (ou pointer)

    La réponse donnée par Anapurna :

    Si tu as les sources de tes objets, regarde si dans le destructor il libère tous les objets créés par lui-même.
    Petit truc si tu utilises des objets libère les avec FreeAndNil(monObjet) plutôt que MonObjet.Free

    Place juste un point d'arrêt dans la procédure de fermeture de ton application. et ensuite vas y à grand coup de F7/F8. Tu pourra ensuite voir l'ordre dans lequel tes objets sont libérés.
    Si tu utilises un composant perso le code du constructor et du destructor serait le bienvenue. De même que le code que tu utilises pour construire et détruire tes objets en runtime.
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    décembre 2012
    Messages
    47
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : décembre 2012
    Messages : 47
    Points : 39
    Points
    39

    Par défaut Patience …

    Merci à tous pour vos réponses.

    Comme vous vous en douter, je manque de temps ces jours-ci pour vous répondre (une réponse longue et documentée vu les questions), je pense en avoir le temps en milieu de semaine.

    En attendant, bonnes fêtes à tous.

  8. #8
    Membre du Club
    Homme Profil pro
    Freelance
    Inscrit en
    novembre 2006
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Freelance

    Informations forums :
    Inscription : novembre 2006
    Messages : 50
    Points : 54
    Points
    54

    Par défaut

    Salut,

    Utilises-tu Heaptrc, pour t'aider a visualiser les objets non libérés ?
    http://wiki.freepascal.org/heaptrc
    C'est super pratique.

    A+ Thierry

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    décembre 2012
    Messages
    47
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : décembre 2012
    Messages : 47
    Points : 39
    Points
    39

    Par défaut

    @Thierry, non je ne connais pas cette unité, mais je vais penser à l'utiliser par la suite. Fonctionne-t-elle aussi pour les objets ?




    J'ai pu résoudre mon problème bien que je n'en comprenne pas bien la raison. D'abord chose curieuse le même programme installé sur des machines différentes provoquait ou pas l'erreur.

    Pour la résolution, j'ai vérifié ligne par ligne dans la méthode de clôture de l'appli ce qui générait l'erreur ; il se trouve que c'était la libération de mon objet principal qui puisqu'il utilisait lui-même d'autres objets et des tableaux dynamiques d'objets avait son destructeur d'implémenté et c'est après y être passé que cela plantait, en sortant.
    J'ai donc simplement déplacé le code dans la méthode de clôture et tout est rentré dans l'ordre.

    Du coup pour la suite il faudra que je comprenne ce qui ne va pas avec le destructeur ; je sais qu'il est appelé par la méthode free, qu'il ne faut pas l'appeler directement mais y a-t-il d'autres précautions ? A l'instant je réalise que la classe dérive d'un TCustomControl dont je n'appelais pas le destructeur, pourrait-ce être l'origine de l'erreur ?

    Voici les lignes importantes du code relatif à cette classe et sa libération

    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
     
    TComposant= class(TCustomControl)
        public
      { paramètres communs }
        nom:string;
        bloc:TStringList;
        description: string;
        fins:array of TFin;                { liste des classes (pointeurs) décrivant une extrémité du composant }
        vue:TVue;
      { commun - table }
        table:string;
        _libele:TLabel;
        photos:TStringList;
      public
        constructor Create(famille:string;idPnp:longword;specs,P:string;d:real;lien:integer;var ext:TFin); overload;
        destructor Destroy; override;
      protected
        procedure ajouteFin(ext: TFin);
    end;
     
    destructor TComposant.Destroy;
      var
        i:integer;
     
      begin
        bloc.Free;
        if (vue<>nil) then
     	vue.Free;    
        photos.Free;
        setlength(fins,0);
      end;
    TVue est une autre classe que j'ai créée qui ne me pose pas de problème. De même pour TFin ; le tableau est juste vidé car les objets sont détruits avant, indépendamment car ils sont partagés à un niveau plus global pour des raisons liées à l'appli et que dans ce cas c'était plus facile à gérer que composant pas composant qui les partagent entre eux ou parce qu'avec le bug, j'ai déplacé le code comme je l'ai fait pour le reste des propriétés du TComposant. J'avais fait de même avec le _libele attaché au composant mais que tous n'ont pas, mais je m'aperçois que je l'ai mis en commentaire sans que ça ne provoque d'erreur ...

    Ensuite je ne fais qu'appeler la méthode free dans une boucle après avoir libérer les éléments
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
                for k:=0 to TLigne(lignes[i]).nbFins-1 do
                  TLigne(lignes[i]).fins[k].free;
              { libérer les composants, leur libelé et leur vue }
    	          for j:=0 to TLigne(lignes[i]).nbComp-1 do
    	            with (TLigne(lignes[i])) do
    		        begin
    		           TComposant(composants[j]).free;
    			end;
                lignes[i].Free;

    Faut-il ajouter un inherited dans le Destructor comme dans le Create, et où (début ou fin de méthode) ?


    Je considère le problème clos mais je laisse le sujet ouvert quelques jours pour que vous puissiez répondre à cette dernière question.

    Merci à tous.

  10. #10
    Membre expert
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mai 2002
    Messages
    2 504
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : mai 2002
    Messages : 2 504
    Points : 3 970
    Points
    3 970

    Par défaut

    Salut

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    destructor TComposant.Destroy;
      var
        i:integer;
      begin
       Inherited;   // si tu ne fait pas d'inherited tu casse la chaine de destruction 
         // ce qui peut provoquer la non libération d'objet 
        bloc.Free;
        vue.Free;    
       photos.Free;
        if  assigned(fins) then  // si <> nil  le reduire
          setlength(fins,0);
      end;
    Pour moi tout ce code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
         for k:=0 to TLigne(lignes[i]).nbFins-1 do
                  TLigne(lignes[i]).fins[k].free;
    n'a rien à faire ici.
    Le fins est dans le TComposant, pas dans le TLigne.

    Crée dans ton objet composant une méthode LibereFins :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     Procedure TComposant.LibereFins;
    var
      k : Integer;
    begin
       for k:=low(fins) to High(fins) do
         if Assigned(fins[k]) Then
            fins[k].free;
    end;
    et insère-la dans le destroy avant
    Après, il y a des petits trucs qui m'interpellent :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        { libérer les composants, leur libelé et leur vue }
           for j:=0 to TLigne(lignes[i]).nbComp-1 do
    	  with (TLigne(lignes[i])) do
    		         TComposant(composants[j]).free;
    	
            lignes[i].Free; //attention à la libération d'une liste il faut mieux commencer par la fin et faire un downto
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    décembre 2012
    Messages
    47
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : décembre 2012
    Messages : 47
    Points : 39
    Points
    39

    Par défaut

    Comme je l'ai précisé, les Tfins sont aussi référencées ailleurs pour plusieurs usages et il est plus facile dans mon cas (et plus rapide pour l'appli) de travailler sur une référence car chaque fin est commune à deux composants (leur point de connexion) sauf aux extrémités libres (une liste intéressante à avoir sous la main) et aussi pour d'autres raisons de fonctionnement interne. Je sais c'est bâtard et ça mériterait une meilleure analyse. Ceci dit, j'avais commencé par libérer ces objets dans TComposant et je les ai sortis pour tenter de résoudre mon problème. C'était l'un ou l'autre et fondamentalement ça ne change rien de ce que j'ai finalement fait avec TVue et les TLabel.


    Pour la libération des listes, bien pris, mais je ne vois pas pourquoi.


    Et pour la libération de la classe parent ? Je viens de chercher l'idée proposée et manifestement il faut bien appeler le destroy parent à la fin : http://www.delphibasics.co.uk/RTL.asp?Name=Destructor
    Un oubli que je vais réparer demain et qui je l'espère résoudra mon problème.

    Merci.

  12. #12
    Membre expert
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mai 2002
    Messages
    2 504
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : mai 2002
    Messages : 2 504
    Points : 3 970
    Points
    3 970

    Par défaut

    Salut

    Effectivement cela est plus judicieux de le mettre en fin comme pour le "constructor", ou il est preferable de le mettre à l'avant .

    Pour la libération des listes, bien pris, mais je ne vois pas pourquoi.
    tu veut dire quoi par ceci
    Tu ne comprends pas pourquoi il faut commencer par la fin, c'est pourtant simple :

    Imagine que tu fais une boucle de 0 a 7.
    Tu enlèves ton 1er élément à chaque tour :
    TAB : [0][1][2][3][4][5][6][7]
    IND : 0 1 2 3 4 5 6 7

    TAB : [0][1][2][3][4][5][6]
    IND : 1 2 3 4 5 6 7

    ...

    TAB : [0][1][2][3][4]
    IND : 3 4 5 6 7
    TAB : [0][1][2][3]
    IND : 4 5 6 7
    Ici on se retrouve en dehors des limites.
    C'est pour cela qu'il est préférable de commencer par l'indice le plus haut.
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  13. #13
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    décembre 2012
    Messages
    47
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : décembre 2012
    Messages : 47
    Points : 39
    Points
    39

    Par défaut C'était donc ça !

    Après test, le inherited final était bien la cause du plantage : avec fermeture correcte, sans plantage.
    Donc j'ai replacé la libération des objets qui dépendent de TComposant dans son destroy (du moins ceux que j'avais récemment déplacés, pas le temps ni de risque à changer trop en profondeur ; ce sera pour une autre occasion maintenant que je le sais.


    Pour la question du tableau dynamique, je ne suis pas d'accord car les cases du tableau restent toujours présentes, c'est le contenu vers lequel elles pointent qui n'a plus de sens. Au mieux, si on fait un FreeandNil, on obtient un tableau de pointeurs nuls, pas différent de celui que je peux construire à l'origine avant toute allocation d'objet. Mais pourquoi pas prendre l'habitude de libérer par la fin afin de ne pas avoir de problème en changeant la dimension du tableau ensuite.


    Cette fois, le test ayant été concluant, je clos la discussion.

    Merci à tous pour vos contributions et comme je m'aperçois que je l'ai oublié hier, meilleurs vœux et bonne année.

  14. #14
    Membre expert
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    mai 2002
    Messages
    2 504
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : mai 2002
    Messages : 2 504
    Points : 3 970
    Points
    3 970

    Par défaut

    Salut

    Je ne parlais pas du tableau mais bien d'une liste même si l'exemple est trompeur.
    Je ne connais pas les objets que tu utilises donc je donnais un conseil pour éviter de se trouver hors limite.
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  15. #15
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    décembre 2012
    Messages
    47
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : décembre 2012
    Messages : 47
    Points : 39
    Points
    39

    Par défaut

    C'est pour les TStringList par exemple si je comprends bien, non.

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

Discussions similaires

  1. [Lazarus] Exception de class 'External: SIGSEGV'
    Par sebBastien dans le forum Lazarus
    Réponses: 8
    Dernier message: 17/09/2014, 03h33
  2. [Python 3.X] Exception après fermeture de l'application
    Par elafitz dans le forum EDI/RAD
    Réponses: 0
    Dernier message: 22/08/2014, 18h56
  3. Réponses: 1
    Dernier message: 17/12/2010, 21h18
  4. Exception a la fermeture d'une application avec c++ builder
    Par lydafree dans le forum C++Builder
    Réponses: 11
    Dernier message: 28/08/2010, 16h46
  5. [Lazarus] GetCurrentDir : exception External SIGSEGV
    Par JP.NUAGE dans le forum Lazarus
    Réponses: 2
    Dernier message: 07/06/2009, 07h59

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