1
votes

Comment réparer les fuites de mémoire valgrind en utilisant la liste liée?

J'ai construit une liste chaînée de jeux, sachant que je ne peux pas ajouter deux fois le même élément à mon jeu, j'ai donc implémenté cette procédure, mais lorsque j'exécute program.adb ci-dessous, j'ai toujours une mémoire qui fuit, en particulier avec Nouvelle_Cellule: = New T_Cellule '(Element, Null); alors je ne comprends pas cette fuite de mémoire.

linked_set.adb final

==19122== Memcheck, a memory error detector
==19122== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==19122== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==19122== Command: ./nombre_moyen_tirages_chainage
==19122== 

*************************** Début ****************************

le nombre moyen de tirages qu’il faut faire pour obtenir tous
les nombres entre 10 et 20 est :  34

***************************** Fin ****************************

==19122== 
==19122== HEAP SUMMARY:
==19122==     in use at exit: 17,600 bytes in 1,100 blocks
==19122==   total heap usage: 1,111 allocs, 11 frees, 24,160 bytes allocated
==19122== 
==19122== 17,600 (1,600 direct, 16,000 indirect) bytes in 100 blocks are definitely lost in loss record 2 of 2
==19122==    at 0x483A7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==19122==    by 0x4AA78CF: __gnat_malloc (in /usr/lib/x86_64-linux-gnu/libgnat-8.so.1)
==19122==    by 0x10C3AB: nombre_moyen_tirages_chainage__ensembles_entiers__ajouter.4561 (ensembles_chainage.adb:59)
==19122==    by 0x10BABD: _ada_nombre_moyen_tirages_chainage (nombre_moyen_tirages_chainage.adb:38)
==19122==    by 0x10B924: main (b~nombre_moyen_tirages_chainage.adb:247)
==19122== 
==19122== LEAK SUMMARY:
==19122==    definitely lost: 1,600 bytes in 100 blocks
==19122==    indirectly lost: 16,000 bytes in 1,000 blocks
==19122==      possibly lost: 0 bytes in 0 blocks
==19122==    still reachable: 0 bytes in 0 blocks
==19122==         suppressed: 0 bytes in 0 blocks
==19122== 
==19122== For lists of detected and suppressed errors, rerun with: -s
==19122== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Et j'ai un programme simple utilisant la méthode ajouter :

nombre_moyen_tirages_chainage.adb
  1 with Ensembles_Chainage;
  2 with Alea;
  3 with Ada.Text_IO; use Ada.Text_IO;
  4 
  5 -- Cette procédure calculera le nombre moyen de tirages qu’il faut
  6 -- faire pour obtenir tous les nombres d’un intervalle entier Min..Max en
  7 -- utilisant le générateur de nombre aléatoire.
  8 procedure Nombre_Moyen_Tirages_Chainage is
  9     Min : Constant integer := 10; -- La borne inférieure.
 10     Max : Constant integer := 20; -- La borne supérieure.
 11     Essais : Constant integer := 100; -- Le nombre d'essais.
 12 
 13     package Mon_Alea is
 14         new Alea (Min, Max);  -- Générateur de nombre dans l'intervalle [1, 10].
 15     use Mon_Alea;
 16 
 17     package Ensembles_Entiers is -- Instantiation du package Ensembles_Chainage.
 18         new Ensembles_Chainage (T_Element => Integer);
 19     use Ensembles_Entiers;
 20 
 21     Ensemble : T_Ensemble; -- Déclarer une variable ensemble.
 22     Moyenne : Integer; -- La variable moyenne qui stockera le nombre moyen de tirages.
 23     n_alea: Integer; -- Le nombre aléatoire généré.
 24 begin
 25     New_Line;
 26     Put_Line("*************************** Début ****************************");
 27     New_Line;
 28     Moyenne := 0; -- Initialiser Moyenne à 0.
 29 
 30     for i in 1..Essais loop
 31         Initialiser (Ensemble); -- Initialiser un ensemble vide.
 32 
 33         loop
 34             Get_Random_Number(n_alea); -- Obtenir un nombre aléatoire.
 35             Moyenne := Moyenne + 1; -- Incrementer Moyenne.
 36 
 37             if not(Est_Present (Ensemble, n_alea)) then
 38                 ajouter (Ensemble, n_alea); -- Ajouter n_alea à l'ensemble.
 39             end if;
 40             exit when Taille (Ensemble) = Max - Min + 1;
 41         end loop;
 42     end loop;
 43 
 44     Moyenne := Moyenne / Essais; -- Calculer la Moyenne.
 45     Put_Line("le nombre moyen de tirages qu’il faut faire pour obtenir tous");
 46     Put_Line("les nombres entre" & Integer'Image(Min) & " et" & Integer'Image(Max) & " est : " & Inte    ger'Image(Moyenne));
 47 
 48    New_Line;
 49    Put_Line("***************************** Fin ****************************");
 50    New_Line;
 51 
 52 end Nombre_Moyen_Tirages_Chainage;

Ensuite, lorsque je compile et exécute avec valgrind ce programme, il affiche une mémoire de fuite liée à ajouter la fonction dans linked_set.adb :

 56     procedure Ajouter (Ensemble : in out T_Ensemble; Element : in T_Element) is
 57         Nouvelle_Cellule, Temp : T_Ensemble;
 58     begin
 59         Nouvelle_Cellule := New T_Cellule'(Element, Null);
 60         if ( Ensemble = Null) then -- Si l'ensemble est vide.
 61                 Ensemble := Nouvelle_Cellule; --Créer une nouvelle cellule.
 62         else -- Sinon, on ajoute à la fin de l'ensemble.
 63                 Temp := Ensemble;
 64 
 65                 while (Temp.all.Suivant /= Null) loop
 66           
 67                         Temp := Temp.all.Suivant;
 68                 end loop;
 69                 Temp.all.Suivant := Nouvelle_Cellule; --Créer une nouvelle cellule.;
 70         end if;
 71     end Ajouter;

Comment puis-je résoudre ce problème s'il vous plaît. Vous trouverez l'intégralité du code dans ma page github: https://github.com / MOUDDENEHamza / pim / tree / master / tp / pr2


1 commentaires

Ada est conçu avec des mots réservés qui sont (presque entièrement) des mots anglais afin que le code résultant se lit un peu comme l'anglais. Lorsque vous choisissez des identifiants qui ne sont pas également composés de mots anglais, vous vous battez contre ce choix de conception et vous rendez votre code plus difficile à lire. De plus, comme il s'agit d'un forum en anglais, lorsque vous publiez un code avec des identifiants et des commentaires non anglais, vous choisissez de présenter à la majorité de vos lecteurs des identifiants et des commentaires dénués de sens, ce qui réduit la quantité et peut-être la qualité des réponses que vous recevez.


3 Réponses :


1
votes

Peut-être avez-vous une fuite lors de la suppression , et non de l ' ajout ?


1 commentaires

Merci, vous êtes totalement la raison pour laquelle la fuite était sur la méthode de suppression.



1
votes

Je pense que vous devez initialiser la liste avant la boucle interne et appeler Detruire (anglais: Destroy) après. Le sous-programme Detruire utilise Ada.Unchecked_Deallocation pour désallouer les éléments de la liste (voir here ) qui étaient précédemment alloués avec (dans ce cas):

procedure Supprimer (Ensemble : in out T_Ensemble; Element : in T_Element) is
begin
   if (Ensemble.all.Element = Element) then
      declare
         Temp : T_Ensemble := Ensemble;
      begin         
         Ensemble := Ensemble.all.Suivant;
         Free (Temp);
      end;         
   else
      Supprimer (Ensemble.all.Suivant, Element);
   end if;
end Supprimer;

Voici l'adaptation: p>

program.adb (partiel)

$ valgrind ./nombre_moyen_tirages_chainage 
==1353== Memcheck, a memory error detector
==1353== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1353== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==1353== Command: ./nombre_moyen_tirages_chainage
==1353== 

*************************** Début ****************************

le nombre moyen de tirages qu’il faut faire pour obtenir tous
les nombres entre 10 et 20 est :  34

***************************** Fin ****************************

==1353== 
==1353== HEAP SUMMARY:
==1353==     in use at exit: 0 bytes in 0 blocks
==1353==   total heap usage: 1,111 allocs, 1,111 frees, 24,339 bytes allocated
==1353== 
==1353== All heap blocks were freed -- no leaks are possible
==1353== 
==1353== For counts of detected and suppressed errors, rerun with: -v
==1353== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

sortie (valgrind)

for i in 1..Essais loop

    Initialiser (Ensemble);   --  Initialize

    loop
        Get_Random_Number(n_alea); -- Obtenir un nombre aléatoire.
        Moyenne := Moyenne + 1; -- Incrementer Moyenne.

        if not(Est_Present (Ensemble, n_alea)) then
            Ajouter (Ensemble, n_alea); -- Ajouter n_alea à l'ensemble.
        end if;
        exit when Taille (Ensemble) = Max - Min + 1;
    end loop;

    Detruire (Ensemble);      --  Destroy

end loop;

Il y a aussi une désallocation manquante dans le sous-programme Supprimer (anglais: remove):

ensembles_chainage.adb (partiel )

Nouvelle_Cellule := New T_Cellule'(Element, Null);


0 commentaires

1
votes

Vous ajoutez des entrées à votre liste liée, mais vous ne les supprimez pas, donc lorsque votre programme se termine, les entrées sont toujours là dans la liste, et valgrind voit cela comme une fuite. Ce n’est pas vraiment le cas: le système d’exploitation nettoiera automatiquement.

Vous pourriez simplement vivre avec cela (je le ferais), mais si vous voulez nettoyer, vous pouvez le faire explicitement comme @DeeDee le suggère, ou vous pouvez explorer la création de votre liste liée (limité) contrôlé .


0 commentaires