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

Delphi Discussion :

Propriété data d'un treenode et libération mémoire


Sujet :

Delphi

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    70
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 70
    Points : 77
    Points
    77
    Par défaut Propriété data d'un treenode et libération mémoire
    Bonjour tout le monde, je viens d'effectuer une recherche sur le forum, mais malheureusement je n'ai pas trouvé de discussion qui traitait de mon problème. Celui est très simple, comment libérer la mémoire associé à une structure dans un Treenode. Voici un exemple de code :

    1- ) Je crée un record, et utilise un pointeur afin de créer ou de récupérer des informations :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    DDonnees = record 
    Nom : String;
    Ville : String;
    CodePostal : String;
    IDLieu : String; 
    end; 
    PDonnees = ^DDonnees;

    2- ) Lors de la creation du TreeView, j'utilise la propriété data du treenode afin de rattacher des informations. Voici un exemple de création de noeud :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Procedure TBlabla.AjoutNoeud;
                  Var PointeurNoeud : PDonnees;
    Begin
    New(PointeurNoeud);
     
    PointeurNoeud.Nom := 'Essai';
    PointeurNoeud.Ville :=  'Strasbourg';
    PointeurNoeud.CodePostal := '67000';
    PointeurNoeud.IDLieu := 'STRA01'; 
     
    NoeudCree := TreeView1.Items.AddChildObject(NoeudParent, PointeurNoeud.Nom+ ' - ' + PointeurNoeud.IDLieu, PointeurNoeud); 
    End;
    Je passe tout les blabla d'affectation d'image etc... L'essentiel est que cela fonctionne très bien, pas de problème pour la création, ni pour le parcours du Treeview ni pour récupérer les valeurs.

    Le problème vient lorsque je ferme la fenêtre. D'après la doc, les structures de données liées à un noeud ne sont pas libérées automatiquement, il faut donc avant la fermeture de la fenêtre libérer toutes les structures. J'ai essayé à l'aide de l'instruction dispose, mais lorsque je regarde le gestionnaire des tâches, la consommation en mémoire de mon programme reste élevée par rapport à ce qu'il consommait avant le peuplement du treeview.

    Voici le code exécuté à la fermeture de la Form

    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
    If (RzTreeView1.Items.Count > 0) Then
    Begin
    // Libération des informations des noeuds
    Noeud := RzTreeView1.Items[RzTreeView1.Items.Count-1];
    While(Noeud <> nil) Do
    Begin
    Noeud1 := Noeud.GetPrev;
    Dispose(Noeud.Data);
    Noeud.Free;
    Noeud := Noeud1; 
    End; 
    End;
     
    // Réinitialisation arborescence
    RzTreeView1.Items.Clear;
    Si quelqu'un a une solution a proposé je suis preneur. Cela fait plusieurs jours que je me casse la tête la dessus sans résultat probant.

    Consommation mémoire avant chargement Treeview : 13252 Ko.
    Consommation mémoire TreeView chargé : 14812 Ko.
    Consommation mémoire après avoir fermé la fenêtre : 14780 Ko.

    Pour info, je travail à partir d'une base de données, et je classe environ 3000 enregistrements dans le Treeview. Le record servant à stocker les infos pour un noeud est composé d'une vingtaine de string.

    En pièce jointe se trouve un copie d'écran permettant de voir a quoi ressemble l'arborescence.

    Merci à tous.
    -----------------------------
    (bouton # )
    Images attachées Images attachées  

  2. #2
    Membre expérimenté
    Homme Profil pro
    Développeur .Net / Delphi
    Inscrit en
    Juillet 2002
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur .Net / Delphi
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2002
    Messages : 738
    Points : 1 745
    Points
    1 745
    Par défaut
    Bonjour,
    C'est normal. La propriété data d'un treeview est un pointeur non typé. Pour libérer la mémoire, il faut que tu transtypes ton pointeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Dispose(PDonnees(Noeud.data))
    Tu indiques de ce fait quel est le type de pointeur dont il faut libérer la mémoire.
    Je pense que ça devrait mieux marcher comme ça (A vérifier, je n'ai pas testé...)
    Bonne journée
    Eb.

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 560
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 560
    Points : 25 153
    Points
    25 153
    Par défaut
    Forcé le type du pointeur, ne devrait pas changer grand chose ... quoi que, le test serait interessant ...
    normalement le MemoryManager gère sa table d'allocation, et donc connait la taille qu'il doit libérér, par contre, il peut dans ce cas libérer les chaines, car en fait, il ne libère qu'un pointeur sur une zone mémoire de 16 octets mais pas les chaines

    parcontre, affecter les chaines à vide avant le dispose, peut aider, il avait un bug en D4 avec la TStringList à ce sujet, et j'ai l'impression, que ça le fait ailleurs ... donc je pense qu'un Finalize serait nécessaire, sinon, souvent, je remplace mes strings par des shortstring !

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    70
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 70
    Points : 77
    Points
    77
    Par défaut And the winner Is....
    Merci à tous les deux pour vos réponses . J'ai testé les deux méthodes et le résultat est le suivant :

    1- Transtypage du pointeur : cela ne règle pas le problème de la mémoire non libérée, cependant cela apporte de la clarté dans le code, par conséquent je l'ai intégré.

    2 - Utilisation de ShortString à la place des String : cela fonctionne, je récupère environ 6 Mo de mémoire lors de la fermeture de la Form. Nous allons essayé de faire remonté le bug à CodeGear.

    Mon problème est donc résolu et j'espère que vos solutions aideront d'autres développeurs.

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 560
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 560
    Points : 25 153
    Points
    25 153
    Par défaut
    Alors, bien vu ebastien, pour le typage ... si l'on ne précise pas, il libère le pointeur et sa mémoire directement associé (FreeMem est appelé en ASM et non pas Dispose, mais ne fait pas le finalize), et si l'on précise, il appele vraiement dipose et donc le finalize, la mémoire est correctement libérée, j'ai fait sur 5000 éléments, je n'ai pas de perte même après avoir clické comme un taré ...

    J'ignore pourquoi cela ne fonctionne pas correctement le transtypage mais moi je n'ai pas de problème et pourtant j'alloue environ 250Ko de chaine, et 50Ko de pointeur/structure

    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
    var
      _RecList: TList;
      MSbn, MSan, MSad: TMemoryStatus;
     
    type
      PRecItem = ^TRecItem;
      TRecItem = record
        S: string;
        I: Integer;
      end;
     
    procedure TFrmTestStructureMemoire.BtnNewMassClick(Sender: TObject);
    var
      irl: Integer;
      pir: PRecItem;
      Cumul: Integer;
    begin
      if Assigned(_RecList) then
         BtnDisposeMass.Click();
     
      GlobalMemoryStatus(MSbn);
      lblBeforeNewMass.Caption := Format('%d o', [MSbn.dwTotalPhys - MSbn.dwAvailPhys]);
     
      _RecList := TList.Create();
     
      Cumul := 0;
      for irl := 1 to 5000 do
      begin
        New(pir);
        pir^.S := Format('Item n°%d : %s', [irl, FormatDateTime('Le dddd d mmmm yyyy à hh:nn:ss zzz', Now())]);
        pir^.I := irl;
        Inc(Cumul, Length(pir^.S) + 8);
        _RecList.Add(pir);
      end;
     
      GlobalMemoryStatus(MSan);
      lblAfterNewMass.Caption := Format('%d o', [MSan.dwTotalPhys - MSan.dwAvailPhys]);
      lblNewPrevision.Caption := Format('%d o', [(_RecList.Capacity * SizeOf(Pointer)) + (_RecList.Count * (SizeOf(PRecItem) + SizeOf(TRecItem))) + Cumul]);
      lblNewReal.Caption := Format('%d o', [(MSan.dwTotalPhys - MSan.dwAvailPhys) - (MSbn.dwTotalPhys - MSbn.dwAvailPhys)]);
    end;
     
    procedure TFrmTestStructureMemoire.BtnDisposeMassClick(Sender: TObject);
    var
      irl: Integer;
    begin
      if Assigned(_RecList) then
      begin
        for irl := 0 to _RecList.Count - 1 do
          Dispose(PRecItem(_RecList.Items[irl]));
     
        _RecList.Free();
        _RecList := nil;
      end;
     
      GlobalMemoryStatus(MSad);
      lblAfterDisposeMass.Caption := Format('%d o', [MSad.dwTotalPhys - MSad.dwAvailPhys]);
      lblFinal.Caption := Format('%d o', [(MSad.dwTotalPhys - MSad.dwAvailPhys) - (MSbn.dwTotalPhys - MSbn.dwAvailPhys)]);
    end;

  6. #6
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 560
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 560
    Points : 25 153
    Points
    25 153
    Par défaut
    En Etudiant, les appels de Dispose dans le Code Source de Delphi, on constate, qu'un pointeur non typé systématiquement casté pour l'appel à dispose ... et cela ce justifie, je viens d'en apprendre une belle aujourd'hui, j'en ai vérifié mes codes, c'est vrai que j'ai peu de string dans mes structures mais de array ou short, ... et que par chance, quand j'ai eu des string, j'indiquais le type du pointeur au dispose !

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 21/09/2011, 11h48
  2. Problème de libération mémoire
    Par chrono23 dans le forum C++
    Réponses: 16
    Dernier message: 07/09/2006, 23h18
  3. Réponses: 3
    Dernier message: 14/03/2006, 05h19
  4. [COM] Libération mémoire
    Par MC2 dans le forum Bibliothèques et frameworks
    Réponses: 5
    Dernier message: 13/01/2006, 16h15
  5. FIREBIRD + APPLI EN C : Problèmes de libération mémoire
    Par lio33 dans le forum Connexion aux bases de données
    Réponses: 4
    Dernier message: 16/09/2005, 09h07

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