2015-11-16 22 views
1

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

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

奖金的问题:有多少猫=^^ =在源代码隐藏? – mjn

+0

只是一个无耻的插件:[寻址指针](http://rvelthuis.de/articles/articles-pointers.html)会告诉你为什么它不像预期的那样工作,还有更多。 –

+0

只是一些友好的批评。你在AddToPrintList中的编码是草率的。您对printString1的分配应该在开始之后;不在之前。并且您在结束后的评论与错误的if语句匹配,例如{> = 5}实际上与> = 4的测试匹配。 –

回答

5

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

更换

Dispose(List[I]); 

Dispose(PrintPointer(List[I])); 

这也是有些奇怪,你通过列表​​作为变量参数和不修改的参考。循环也很奇怪,没有理由倒退,循环边界以奇怪的方式处理。我有这些功能是这样的:

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;