TList中的内存泄漏

时间:2015-11-10 20:47:43

标签: delphi delphi-7

使用TList时出现内存泄漏问题。我试图填充填充列表中的Tlist循环并使用数据。下面的代码只是用于填充不使用它的列表的代码。

private
  { Private Form Variable declarations }
  GlblCancel : Boolean;
  MyPrintLst : TList;

PrintRecord = record
  PrintString1,
  PrintString2,
  PrintString3,
  PrintString4,
  PrintString5,
  PrintString6 : string;
  PrintFloat1,
  PrintFloat2,
  PrintFloat3  : Double;
end;
PrintPointer = ^PrintRecord;

Procedure TMyForm.Create;
begin
  MyPrintLst := TList.Create;
end

Procedure TMyForm.FreeTList(Var List : Tlist; Size : Integer);
Var I, Count : Integer;
begin
  Count := list.Count - 1;
  For I := Count DownTo 0 Do
     FreeMem(List[I], Size);
  List.Clear;
  List.Free;
end;

Procedure TMyForm.FormClose;
begin
  FreeTList(MyPrintLst,SizeOf(PrintRecord));
end

procedure AddToPrintList(PrintList : TList;
                         Const MyStrings : Array of String;
                         Const MyDoubles : Array of Double);
var
PrintPtr : PrintPointer;
begin
New(PrintPtr);
IF High(MyStrings) >= 0 Then
   PrintPtr^.printString1 := MyStrings[0];
 Begin
   IF High(MyStrings) >= 1 Then
    Begin
      PrintPtr^.printString2 := MyStrings[1];
      IF High(MyStrings) >= 2 Then
       Begin
         PrintPtr^.printString3 := MyStrings[2];
         IF High(MyStrings) >= 3 Then
          Begin
            PrintPtr^.printString4 := MyStrings[3];
            IF High(MyStrings) >= 4 Then
               PrintPtr^.printString5 := MyStrings[4];
             Begin
               IF High(MyStrings) >= 5 Then
                  PrintPtr^.printString6 := MyStrings[5];
             End; {>=5}
          End; {>=4}
       End; {>=3}
    End; {>=2}
 End; {>=1}
IF High(MyDoubles) >= 0 Then
 Begin
   PrintPtr^.PrintFloat1 := MyDoubles[0];
   IF High(MyDoubles) >= 1 Then
    Begin
      PrintPtr^.PrintFloat2 := MyDoubles[1];
      IF High(MyDoubles) >= 2 Then
         PrintPtr^.PrintFloat3 := MyDoubles[2];
    End;
 End;
PrintList.add(PrintPtr);
end;

Procedure TMyForm.Button1.Click;
Var EstReading : LongInt;
begin
EstReading := 0;
ClearTList(MyPrintLst,Sizeof(PrintRecord));
MyQuery.First;
While Not(MyQuery.EOF) Do
 begin
   EstReading := EstReading + 1;
   AddToPrintList(MyPrintLst, [MyQuery.FieldByName('Field1').AsString,
                               MyQuery.FieldByName('Field2').AsString, 
                               MyQuery.FieldByName('Field3').AsString, 
                               MyQuery.FieldByName*'Field4').AsString, 
                               MyQuery.FieldByName('Field5').AsString, 
                               MyQuery.FieldByName('Field6').AsString],
                               [EstReading]);
   MyQuery.Next;
 end;
end

1 个答案:

答案 0 :(得分:12)

您没有正确处理动态分配的记录。您的记录是受管理的,因为它包含托管类型,在这种情况下为字符串。

当像这样动态分配时,托管类型需要使用New进行分配,并使用Dispose取消分配。您的错误是使用FreeMem而不是Dispose。后者将在记录中处理托管类型,前者不会。因此你的泄漏。

ClearTList似乎有相同的缺陷。

您将指针存储在TList实例中,此类型存储无类型指针。处理每个项目时,必须将项目转换回适当的指针类型,以便运行时知道如何处理记录中的字段。因此,您对Dispose的调用将如下所示:

Dispose(PrintPointer(List[I]));

另外,在调用FreeMem时传递元素的大小是没有意义的。

总结:

  • 对于非托管类型,请使用GetMem/FreeMemNew/Dispose
  • 对于托管类型,请使用New/Dispose
  • 始终正确配对这些功能。始终FreeMem GetMemDispose始终New