I am working on a (multi) client - server environment using PolyORB (DSA personality) by Adacore.
I have one shared passive partition which basically contains a protected type (array) which gets updated by the server with info coming from the clients every second, on a non-stop basis.
I have created a very simple main unit with an infinite loop just to monitor the content of that array.
As expected, printing out the rows of the array every second on the standard output is consuming the memory of the system.
I would like to avoid, if possible, the solution of printing out the info on a file, and run a tail -f command. I would not like to mess around with the disk, the number of clients now is limited but it is expected to grow and performance might get compromised.
On the other hand, I have tried through scripting to kill the monitor and launch it again, but somehow it does seem to work only once. I killed it, and then launched again (OK), then kill it again and the launched (not OK).
Is there a good way to print out a lot of info on the standard output using and infinite loop and not running out of memory?
I have checked there is no other issue causing the memory leak, if no info is printed out on the terminal, there is no problem with the memory.
This is the code of that monitor main unit
with Ada.Text_IO;
with Shared_Table;
with GNAT.OS_Lib;
procedure monitor is
-- Variables to run linux command clear
ARGUMENTS : GNAT.OS_Lib.Argument_List := (1 => new String'(""));
RESULT : Boolean := False;
begin
loop
-- Clearing the terminal after writing the content of the table.
GNAT.OS_Lib.Spawn (Program_Name => "/usr/bin/clear",
Args => ARGUMENTS,
Success => RESULT);
-- Printing out the content of the table on the standard output.
Shared_Table.Visualize_Table (Shared_Table.Obtain_Table);
delay 1.0;
end loop;
end monitor;
Thanks!
Here it is the code of the procudure to print out the rows of the array which is likely to be causing the memory leak.
procedure Visualize_Table (Shared_Table : in Shared_Table_Type) is
-- Very big varibale containing adaptation data in a simple linked list.
Adaptation_Data : Adaptation.Track_List.List;
-- Segment type is a record. One of the components being a simple linked list of items.
Segment_Aux : Segment.Segment_Type;
-- Track Type is a record. One of the components being a simple linked list of segments.
Track_Aux : Track.Track_Type;
Number_of_items : Natural range 1 .. 3 := 1;
begin
-- Load adaptation data.
Adaptation.Generate_Track_List (Adaptation_Data);
-- Visualize header.
Ada.Text_Io.Put_Line (" +-----------+---------------------------------+---------+---------------------------------+-------------+");
Ada.Text_Io.Put_Line (" | xxxxxxxxx | xxxxxxxxxxxx | # Items | xxxxxxxxxxxxxxx | xxxxxxxxx |");
Ada.Text_Io.Put_Line (" +-----------+---------------------------------+---------+---------------------------------+-------------+");
for I in 1 .. Number_of_clients loop
-- Visualize first two columns.
Ada.Text_Io.Put (" | " & Shared_Table(I).First_Row & " | ");
Ada.Text_Io.Put (Shared_Table(I).Second_Row & "| ");
-- Initialize auxiliar variables..
Track.Initialize_Track (Track_Aux);
Segment.Initizalize (Segment_Aux);
Track.Set_Id (Id => Shared_Table(I).Track_Id,
Track => Track_Aux);
Segment.Set_Position (Position => Shared_Table(I).Position,
Segment => Segment_Aux);
Number_of_items :=
Segment.List_of_items.Obtain_Number
(Segment.Obtain_List_of_items
(Track.List_of_segments.Find_Element
(Element => Segment_Aux,
List => Track.Obtain_Segment_List (Adaptation.Track_List.Find_Element (Element => Track_Aux,
List => Adaptation_Data)))));
Ada.Text_Io.Put (" |");
Ada.Text_Io.Put (" X : ");
Ada.Integer_Text_Io.Put (Item => Shared_Table(I).Position_X,
Width => 7);
Ada.Text_Io.Put (" Y : ");
Ada.Integer_Text_Io.Put (Item => Shared_Table(I).Position_Y,
Width => 7);
Ada.Text_Io.Put (" |");
Ada.Integer_Text_Io.Put (Item => Shared_Table(I).Last_Row,
Width => 3);
Ada.Text_Io.Put_Line (" |");
Ada.Text_Io.Put_Line
(" +-----------+---------------------------------+---------+---------------------------------+-------------+");
end loop;
end Visualize_Table;
My understanding is that the variables life should end when the procedure finishes printing out the rows of the array, and the memory used by them should then be free, but given some of the variables are linked list (using access types), that may not be the case, is that possible?
This is part of the log obtained by usgin valgrind
==17190== 61,799,120 (7,774,208 direct, 54,024,912 indirect) bytes in 60,736 blocks are definitely lost in loss record 816 of 816
==17190== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17190== by 0x68D12E: __gnat_malloc (in /home/hector/ITS/distributed/src/monitor)
==17190== by 0x691C7C: system__pool_global__allocate (in /home/hector/ITS/distributed/src/monitor)
==17190== by 0x4CFD16: adaptation__track_list__insert_element (in /home/hector/ITS/distributed/src/monitor)
==17190== by 0x4D6028: adaptation__generate_track_list (in /home/hector/ITS/distributed/src/monitor)
==17190== by 0x4D991C: shared_table__visualize_table (in /home/hector/ITS/distributed/src/monitor)
==17190== by 0x4DB9FE: _ada_monitor (in /home/hector/ITS/distributed/src/monitor)
==17190== by 0x47926F: partition___elabb (in /home/hector/ITS/distributed/src/monitor)
==17190== by 0x47BA56: adainit (in /home/hector/ITS/distributed/src/monitor)
==17190== by 0x47BAC1: main (in /home/hector/ITS/distributed/src/monitor)
I can see some other memory leaks all of the ultimately pointing to the instantiation of the procedure to insert new elements in a simple linked list.
This is the code of the generic package.
procedure Insert_Element (Element : in Type_Element;
List : in out Type_List) is
Pointer_to_Cell : Type_Pointer_to_Cell := new Type_Cell'(Record_Element => Element,
Record_Pointer => List.Record_Initial_Cell);
begin
if List.Record_Number_of_elements <= Max_Number_of_elements then
List.Record_Initial_Cell := Pointer_to_Cell;
List.Record_Number_of_elements := List.Record_Number_of_elements + 1;
else
raise List_Full_Exception;
end if;
end Insert_Element;
How can I deallocate the memory used by Adaptation_Data once I do not need it anymore?