2015-11-10 24 views
1

使用TList時出現內存泄漏問題。我試圖通過填充列表填充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 
+0

請添加泄漏消息和所有將產生泄漏的代碼 –

回答

12

您沒有正確處置動態分配的記錄。您的記錄是託管的,因爲它包含託管類型,在這種情況下是字符串。

託管類型,當像這樣動態分配時,需要分配爲New,並用Dispose解除分配。你的錯誤是使用FreeMem而不是Dispose。後者將處理記錄中的託管類型,前者不會。因此你的泄漏。

ClearTList可能有相同的缺陷。

您正在將指針存儲在TList實例中,並且此類型存儲無類型的指針。處理每個項目時,必須將項目轉回適當的指針類型,以便運行時知道如何處理記錄中的字段。所以,你要Dispose調用將是這樣的:

Dispose(PrintPointer(List[I])); 

順便說一句,傳遞元素的大小時調用FreeMem是毫無意義。

總結:

  • 對於非託管類型使用GetMem/FreeMem,或New/Dispose
  • 對於託管類型使用New/Dispose
  • 務必正確配對這些功能。總是FreeMemGetMem,總是DisposeNew
+0

調用清除是毫無意義的,因爲您銷燬該對象。因爲您不修改變量,因此將列表作爲'var'傳遞是毫無意義的。無論如何,我想我回答了你問的問題不是? –

+0

我將freetlist過程中的freemem和cleartlist過程更改爲Dispose,並且仍然出現內存泄漏。 – SCAJason

+0

我回答了你問的問題。大概你有其他缺陷。指望我們調試我們看不到的其他代碼是不公平的。如果你提供了[mcve],我們可以在那裏修復所有的代碼。但你沒有。順便說一句,編寫'Count:= List.Count-1'真的很奇怪。使用「計數」來計數,而不是計數。這是沒有必要做一個局部變量。去掉它。 –