Как исправить утечки памяти в valgrind с помощью списка linekd? - PullRequest
1 голос
/ 09 ноября 2019

Я создал связанный список наборов, известный тем, что я не могу добавить один и тот же элемент два раза к своему набору, поэтому я реализовал эту процедуру, но когда я запускаю program.adb ниже, у меня все еще остается утечка памяти, особенно с Nouvelle_Cellule: = New T_Cellule '(Element, Null); тогда я не понимаю эту утечку памяти.

connected_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;

И у меня есть простая программа, использующая 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;

Затем, когда я компилирую и выполняю с помощью valgrind эту программу, она отображает утечку памяти, связанную с функцией ajouter, в connected_set.adb:

==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)

Как я могуисправить эту проблему, пожалуйста. Вы найдете весь код на моей странице github: https://github.com/MOUDDENEHamza/pim/tree/master/tp/pr2

Ответы [ 3 ]

1 голос
/ 09 ноября 2019

Я думаю, вам нужно инициализировать список до внутреннего цикла и затем вызывать Detruire (англ .: Destroy). Подпрограмма Detruire использует Ada.Unchecked_Deallocation для освобождения элементов списка (см. здесь ), которые ранее были выделены (в данном случае):

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

Вот адаптация:

program.adb (частично)

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;

вывод (valgrind)

$ 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)

Также отсутствует пропуск вподпрограмма Supprimer (англ .: удалить):

ensembles_chainage.adb (частично)

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;
1 голос
/ 09 ноября 2019

Вы добавляете записи в свой связанный список, но не удаляете их, поэтому, когда ваша программа завершает работу, записи все еще находятся в списке, и valgrind считает это утечкой. Это не совсем так: операционная система будет очищаться автоматически.

Вы можете просто жить с этим (я бы), но если вы хотите очистить, вы можете сделать это явно, как предлагает @DeeDee, или выможно изучить создание вашего связанного списка (ограниченный), контролируемый .

1 голос
/ 09 ноября 2019

Возможно, вы пропустили , удалив , а не добавив ?

...