附件是我遇到的内存泄漏示例的完整代码。有人可以告诉我如何清理这个内存泄漏。如果您创建一个表单并在其上放置一个按钮,然后将下面的代码粘贴到.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.
答案 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;