Hello,
When class has record property, access to this property cause memory leak. Explicit record destroy doesn't help.
What should I do to get rid of memory leak?
Simplified example to reproduce the problem:
------------------------------------------------
Delphi code:
------------------------------------------------
type
TRec = record
I: Integer;
end;
TTest = class
FRec: TRec;
constructor Create;
property Rec: TRec read FRec;
end;
constructor TTest.Create;
begin
FRec.I := 55;
end;
...
Scripter.DefineRecordByRTTI(TypeInfo(TRec));
Scripter.DefineClassByRTTI(TTest);
...
// Get memory leak (report below) only if run script without R.Free;
ShowMessage(Scripter.ExecuteSubroutine('test_rec'));
...
// Get memory leak (repot below)
ShowMessage(Scripter.ExecuteSubroutine('test_class_rec'));
...
------------------------------------------------
Script:
------------------------------------------------
function test_rec;
var
R: TRec;
begin
R := TRec.Create;
R.I := 44;
Result := IntToStr(R.I);
R.Free;
end;
function test_class_rec;
var
T: TTest;
begin
T := TTest.Create;
Result := IntToStr(T.Rec.I);
// T.Rec.Free; // doesn't help !!!
T.Free;
end;
------------------------------------------------
memory leak report:
------------------------------------------------
An unexpected memory leak has occurred. The unexpected small block leaks are:
1 - 12 bytes: TObject x 2, Unknown x 3
13 - 20 bytes: TPoolToken x 1, TRttiPool x 1
21 - 28 bytes: TValueDataImpl x 1, TRttiInstancePropertyEx x 1, TRttiOrdinalType x 1, TRttiRecordField x 1, TRttiInstanceFieldEx x 1
29 - 36 bytes: TRttiRecordType x 1
37 - 44 bytes: TOrphanPackage x 1
45 - 52 bytes: TRttiInstanceType x 2, TRealPackage x 1
53 - 60 bytes: TGenericRecordWrapper x 1, TObjectDictionary<System.Pointer,System.Rtti.TRttiObject> x 2
61 - 68 bytes: Unknown x 1
189 - 204 bytes: Unknown x 1
TIA and best regards
In my tests here the first routine (test_rec) doesn't leak memory. As for the second, the record wrapper is created whenever scripter needs to "convert" a record value to the wrapper. When you do T.Rec.Free you are actually creating a wrapper on the fly and then destroying it. This is the way to code it so that it doesn't leak:
function test_class_rec;
var
T: TTest;
R: TRec;
begin
T := TTest.Create;
R := T.Rec;
Result := IntToStr(R.I);
R.Free;
T.Free;
end;
Wagner R. Landgraf2017-04-03 13:13:42
Thank you!
Using the record property in this way is not reasonable. In this case, it is better to add new class property for each record field. Do you have a better idea?
And indeed, function test_rec() doesn't leak memory. I just wanted to say that I got same memory leak report if R.Free in test_rec() is omitted, and therefore, I can be sure what causes memory leak in test_class_rec().
Unfortunately that's the way it is. Note that even in Delphi having such a record property has some strange behaviors. For example, doing something like this (in Delphi):