Interface Unknown
Interface Unknown

Reputation: 713

How to correctly dispose array of strings to prevent memory leaks?

MadExcept says my app leaks "strings" memory on the following code:

for i := 0 to TotalSpans-1 do
begin
  if i = 0 then LastPos := 1;
  StartPos := PosEx(SubstrAtBegin, RawHtmlStr, LastPos);
  FinishPos := PosEx(SubstrAtEnd, RawHtmlStr, LastPos);
  Spans[i] := Copy(RawHtmlStr, StartPos, FinishPos - StartPos +
    Length(SubstrAtEnd));
  LastPos := FinishPos + Length(SubstrAtEnd);
end;

where Spans is an array of string.
The idea is to find the specific values in a long RawHtmlStr. For that purpose I first locate the well-known adjacent substrings and then copy the value from between them to a dynamic array of strings.

The whole thing is serialized to work in threads.
On the last run I parsed about 15k of RawHtmlStrs and there were 38 exceptions thrown (mostly EIdReadTimeout and EIdSocketError). I handled those exceptions on an upper lever (simply moving to the next item), but they somehow led to 34 UnicodeString leaks.

madExcept points to the following line:

Spans[i] := Copy(RawHtmlStr, StartPos, FinishPos - StartPos +
    Length(SubstrAtEnd));

as a source of evil.

At the moment the whole piece of code is NOT wrapped by try..finally block because I do not quite understand how to handle the disposal of string array (which, I thought, is being taken care of by Delphi, no?).

Will Finalize(Spans) do the garbage collection in this case?

Upvotes: 2

Views: 1375

Answers (1)

David Heffernan
David Heffernan

Reputation: 613332

The object in question is of type

array of string

That is a dynamic array whose lifetime is managed by reference counting. The members of the array also have lifetime managed by reference count.

With managed objects you do not need to take any steps to dispose of them. At some point, when the final reference to the object leaves scope, the object is automatically destroyed.

So, if you are leaking such an object that would usually imply that whatever contains the object is not being destroyed. For example, this code would leak an array of strings:

type
  TRec = record
    arr: array of string;
  end;
  PRec = ^TRec;
....
var
  Rec: PRec;
....
New(Rec);
SetLength(Rec.arr, 42);
Rec.arr[0] := 'foo';
// and so on

If you failed to dispose of Rec then it, and its contents, would be leaked.

Likewise if you have a class that owns managed objects, and that class is leaked, then all the members of the class are also leaked.

type
  TMyClass = class
    arr: array of string;
  end;
....
var
  Obj: TMyClass;
....
Obj := TMyClass.Create;
SetLength(Obj.arr, 42);
Obj.arr[0] := 'foo';
// and so on

Again, if you fail to destroy Obj, then it will leak, and so will its members.

Beyond that scenario, the only other way that I can imagine a managed type leaking is if a heap corruption overwrites the reference count.

Upvotes: 4

Related Questions