Terminal 将日志放在无限循环生成的标准输出上的最佳方式是什么?
我正在使用Adacore的PolyORB(DSA个性)开发一个(多)客户机-服务器环境 我有一个共享的被动分区,它基本上包含一个受保护的类型(数组),服务器每秒用来自客户端的信息不间断地更新它 我创建了一个带有无限循环的非常简单的主单元,用于监视该数组的内容 正如预期的那样,在标准输出上每秒打印一次数组行会消耗系统内存 如果可能的话,我希望避免在文件上打印信息,并运行tail-f命令。我不想乱搞磁盘,现在客户端的数量是有限的,但它预计会增长,性能可能会受到影响 另一方面,我尝试通过脚本杀死监视器并再次启动它,但不知何故,它似乎只工作一次。我杀了它,然后再次启动(OK),然后再次杀了它,然后启动(不OK) 有没有一种好方法可以在不耗尽内存的情况下,使用无限循环打印出大量关于标准输出的信息 我已经检查过没有其他问题导致内存泄漏,如果终端上没有打印信息,则内存没有问题 这是监视器主机的代码Terminal 将日志放在无限循环生成的标准输出上的最佳方式是什么?,terminal,memory-leaks,infinite-loop,ada,Terminal,Memory Leaks,Infinite Loop,Ada,我正在使用Adacore的PolyORB(DSA个性)开发一个(多)客户机-服务器环境 我有一个共享的被动分区,它基本上包含一个受保护的类型(数组),服务器每秒用来自客户端的信息不间断地更新它 我创建了一个带有无限循环的非常简单的主单元,用于监视该数组的内容 正如预期的那样,在标准输出上每秒打印一次数组行会消耗系统内存 如果可能的话,我希望避免在文件上打印信息,并运行tail-f命令。我不想乱搞磁盘,现在客户端的数量是有限的,但它预计会增长,性能可能会受到影响 另一方面,我尝试通过脚本杀死监视器
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;
谢谢
这里是打印出可能导致内存泄漏的数组行的程序代码
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;
我的理解是,当过程完成打印出数组的行时,变量的生命应该结束,它们使用的内存应该是空闲的,但是如果某些变量是链表(使用访问类型),那么情况可能不是这样,这是可能的吗
这是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)
我可以看到其他一些内存泄漏,所有这些最终都指向在简单链表中插入新元素的过程的实例化
这是通用包的代码
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;
过程插入元素(元素:在类型元素中;
列表:输入输出类型(列表)为
指针指向单元格:类型指针指向单元格:=新类型单元格'(记录元素=>元素,
记录\u指针=>List.Record\u初始单元格);
开始
如果元素的List.Record\u Number\u使用循环缓冲区的一般受保护对象可以如下所示:
-----------------------------------------------------------------------
-- Generic Bounded Protected Queue
-----------------------------------------------------------------------
generic
type Element_Type is private;
type Queue_Index is mod <>;
package Generic_Protected_Bounded_Queue is
type Buffer is array (Queue_Index) of Element_Type;
protected type Queue is
function Capacity return Natural;
function Is_Full return Boolean;
function Is_Empty return Boolean;
entry Enqueue (Value : in Element_Type);
entry Dequeue (Value : out Element_Type);
procedure Clear;
private
Buf : Buffer;
Head : Queue_Index := 0;
Tail : Queue_Index := 0;
Count : Natural := 0;
end Queue;
end Generic_Protected_Bounded_Queue;
当然,由于外部循环,任务会占用大量CPU资源。该循环执行轮询操作,而不是等待数据可用。共享表应实现为一个有界缓冲区。当缓冲区为空时,读取任务将挂起,并且仅当数据可用时才读取数据
请参见以下使用有界队列包的示例:
with Ada.Text_IO; use Ada.Text_IO;
with generic_protected_bounded_queue;
procedure Main is
type Index_T is mod 10;
package int_queue is new generic_protected_bounded_queue(Element_Type => Integer,
Queue_Index => Index_T);
use int_queue;
The_Queue : Queue;
task producer;
task body producer is
begin
Put_Line("Producer started.");
for Num in 1..20 loop
The_Queue.Enqueue(Num);
Put_Line("Enqueued" & Num'Image);
end loop;
Put_Line("Producer terminating.");
end Producer;
task consumer;
task body consumer is
Num : Integer;
begin
Put_Line("Consumer started.");
for Val in 11..30 loop
The_Queue.Dequeue(Num);
Put_Line("Dequeued" & Num'Image);
end loop;
Put_Line("Consumer terminating.");
end Consumer;
begin
null;
end Main;
不是PolyORB的专家,只是一些需要澄清的问题。现在还不完全清楚监视器程序在您第二次启动时是如何失败的。它是报告内存错误还是只是挂起?你看到内存消耗失控了吗?它是否真的重新加入/重新连接到(DSA)程序并接收新数据?在您终止监控程序后,DSA应用程序的其余部分是否仍能正常运行?您是否可以给出一些指示,说明每次循环迭代要向输出输出打印多少行/字符,以了解内存可能会成为问题的原因?第二次尝试重新启动监视器时,它看起来像是挂起了,标准输出上没有打印出任何内容。记忆绝对不是失控的。顺序如下,第一次运行(OK),第二次运行(OK)后续运行(not OK)。在我关闭监视器后,DSA应用程序的其余部分保持平稳运行。在每次迭代中,打印的文本不超过7行,每行不超过107个字符。如何同步对Shared_Table
的访问?如果将对Spawn
的调用更改为Ada.text_IO.New_行(间距=>100),会发生什么情况
?@trashgod访问的对象数组是受Ada保护的类型。当我调用函数来获取数组时,我实际上使用了受保护对象本身的函数,这保证了在我访问数据时数据不会被写入。换句话说,没有同步,值得一试。至少它给了我一条新的探索之路。我会在这里张贴的结果,一旦我可以测试它。谢谢!我刚刚完成了这种方法的测试,我担心内存消耗要高得多(几乎高出3倍)。我应该指出,客户端每秒都会向服务器发送更新的信息。您能显示日志任务的代码吗?每秒一次非常慢。任务应该挂起,直到在缓冲区中读取数据。一旦数据准备好,任务应该读取数据,记录它,然后再次尝试读取缓冲区。在1秒的大部分时间内,日志记录任务应该挂起,不使用CPU。Shared_表是在Shared_被动包中定义的,只有无entryless保护类型才可用。我需要通过不同的分区以可靠的方式访问数据。设计共享_表的人做得很差。
task Visualize_Data;
task body Visualize_Data is
Arguments : GNAT.OS_Lib.Argument_List := (1 => new String'(""));
Result : Boolean := False;
begin
loop
if Shared_Table.Obtain_Rows > 0 then
Shared_Table.Visualize_Header;
for I in 1 .. Shared_Table.Obtain_Rows loop
declare
Row : Shared_Table.Row;
begin
Bounded_Buffer.Queue.Dequeue (Row);
Shared_Table.Visualize_Row (Row);
end;
end loop;
GNAT.OS_Lib.Spawn (Program_Name => "/usr/bin/clear",
Args => Argument,
Success => Result);
end if;
end loop;
end Visualize_Data;
with Ada.Text_IO; use Ada.Text_IO;
with generic_protected_bounded_queue;
procedure Main is
type Index_T is mod 10;
package int_queue is new generic_protected_bounded_queue(Element_Type => Integer,
Queue_Index => Index_T);
use int_queue;
The_Queue : Queue;
task producer;
task body producer is
begin
Put_Line("Producer started.");
for Num in 1..20 loop
The_Queue.Enqueue(Num);
Put_Line("Enqueued" & Num'Image);
end loop;
Put_Line("Producer terminating.");
end Producer;
task consumer;
task body consumer is
Num : Integer;
begin
Put_Line("Consumer started.");
for Val in 11..30 loop
The_Queue.Dequeue(Num);
Put_Line("Dequeued" & Num'Image);
end loop;
Put_Line("Consumer terminating.");
end Consumer;
begin
null;
end Main;