Frans Whyburd wrote:
Does the following code have a memory leak ?
type
rRecord = record
i : integer;
str : string;
end;
pRecord = ^rRecord;
procedure TForm1.testForLeak;
var
i : integer;
s : string;
pnt : pRecord;
list : Tlist;
begin
list := Tlist.create;
for i := 0 to 1000000 do
begin
new(pnt);
pnt.l1 := 1;
pnt.l2 := 'a';
Error: Undeclared identifier: 'l1'
Error: Undeclared identifier: 'l2'
*Always* copy and paste your *real* code.
list.Add(pnt);
end;
for i := 0 to list.Count -1 do
begin
dispose(list.Items[i]);
end;
Yes, this code has a memory leak. The Dispose procedure is a
compiler-magic routine. It knows how much memory to free, and how to
free it, based on the type of the pointer you pass to it. Likewise with
the New procedure.
You pass a PRecord to New. It allocates SizeOf(TRecord) bytes, and then
it initializes the str field of the record to ensure it holds a valid
string value. (If you use GetMem to allocate the record, the str field
remain uninitialized, and using it will probably result in an access
violation. That's why we have the Initialize procedure.)
The pointer you pass to Dispose is just of type Pointer, not PRecord.
That's because Pointer is the declared type of the TList.Items property.
Therefore, Dispose doesn't know that there is a str field, so it doesn't
do anything about freeing the string's memory. So you're leaking at
least 10 bytes per record (the number of bytes in the string data), and
probably more, based on the allocation granularity of the memory manager.
To fix the problem, do this:
for i := 0 to Pred(list.Count) do begin
pnt := list[i];
Dispose(pnt);
end;
It isn't necessary to call Clear before you free the TList; the list's
destructor does that for you already.
Actually, in the particular code you showed, there *isn't* a memory
leak. That's because the 'a' string literal is stored as a constant in
your program's data segment -- it doesn't get allocated from the heap.
Each instance of the str field holds a reference to the same string.
Even if you called Dispose properly, the memory for those strings would
never get freed because the memory manager never allocated them.
In general, though, I assume those strings won't all come from
constants, and so you will eventually leak memory.
--
Rob
__________________________________________________
Delphi-Talk mailing list -> [email protected]
http://www.elists.org/mailman/listinfo/delphi-talk