使用tlist在完整Delphi代码中泄漏内存

时间:2015-11-16 18:41:03

标签: delphi memory-leaks delphi-7

附件是我遇到的内存泄漏示例的完整代码。有人可以告诉我如何清理这个内存泄漏。如果您创建一个表单并在其上放置一个按钮,然后将下面的代码粘贴到.pas文件中,则可以编译此代码。提前感谢您提供的任何帮助。

unit LeakForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
type PrintRecord = record
  PrintString1,
  PrintString2,
  PrintString3,
  PrintString4,
  PrintString5,
  PrintString6 : string;
  PrintFloat1,
  PrintFloat2,
  PrintFloat3  : Double;
end;
PrintPointer = ^PrintRecord;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
    MyPrintLst : TList;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
procedure ClearTList(Var List : TList);
Var I, Count : Integer;
begin
  Count := list.Count - 1;
  For I := Count DownTo 0 Do
     Dispose(List[I]);
  List.Clear;
end;
procedure FreeTList(Var List : TList);
Var I, Count : Integer;
begin
  ClearTList(List);
  List.Free;
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 TForm1.Button1Click(Sender: TObject);
Var EstReading : LongInt;
begin
EstReading := 0;
ClearTList(MyPrintLst);
AddToPrintList(MyPrintLst, ['Field1 Data','Field2 Data','Field3 Data','Field4 Data'],
                           [1,2,3,4]);
AddToPrintList(MyPrintLst, ['Field1 Data','Field2 Data','Field3 Data','Field4 Data'],
                           [5,6,7,8]);
AddToPrintList(MyPrintLst, ['Field1 Data','Field2 Data','Field3 Data','Field4 Data'],
                           [9,0,1,2]);
AddToPrintList(MyPrintLst, ['Field1 Data','Field2 Data','Field3 Data','Field4 Data'],
                           [3,4,5,6]);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MyPrintLst := TList.Create;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeTList(MyPrintLst);
end;

end.

1 个答案:

答案 0 :(得分:5)

当您处理每个项目时,运行时需要知道记录的类型。因为您使用的是TList,所以每个项目都是无类型指针。因此,您需要将指针强制转换为项类型,以便运行时知道类型,并知道如何处置该项。

替换

Dispose(List[I]);

Dispose(PrintPointer(List[I]));

将列表作为var参数传递并且不修改引用也有点奇怪。循环也很奇怪,无缘无故地向后运行,循环边界以奇怪的方式处理。我有这样的功能:

procedure ClearTList(List: TList);
Var
  I: Integer;
begin
  For I := 0 to List.Count - 1 Do
    Dispose(PrintPointer(List[I]));
  List.Clear;
end;

procedure FreeTList(List: TList);
begin
  ClearTList(List);
  List.Free;
end;

更传统的命名惯例是:

type
  TPrintRecord = record
    ....
  end;
  PPrintRecord = ^TPrintRecord;

如果表单在关闭时具有OnClose操作,则可以多次调用表单的caHide事件。与OnCreate配对的正确事件为OnDestroy

AddToPrintList中逻辑的复杂性使我相信数据类型可以更好地设计。数组表明自己而不是单独编号的字段。

在不更改类型的情况下,您至少应该避免所有缩进,例如:

procedure AddToPrintList(PrintList: TList; const MyStrings: array of String;
  const MyDoubles: array of Double);
var
  I: Integer;
  Item: PPrintRecord;
  Str: string;
  Value: Double;
begin
  New(Item);
  PrintList.Add(Item);

  for I := 1 to Min(Length(MyStrings), 6) do
  begin
    Str := MyStrings[I - 1];
    case I of
    1:
      Item.PrintString1 := Str;
    2:
      Item.PrintString2 := Str;
    3:
      Item.PrintString3 := Str;
    4:
      Item.PrintString4 := Str;
    5:
      Item.PrintString5 := Str;
    6:
      Item.PrintString6 := Str;
    end;
  end;

  for I := 1 to Min(Length(MyDoubles), 3) do
  begin
    Value := MyDoubles[I - 1];
    case I of
    1:
      Item.PrintFloat1 := Value;
    2:
      Item.PrintFloat2 := Value;
    3:
      Item.PrintFloat3 := Value;
    end;
  end;
end;