class wit record property - memory leak

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):


T.Rec.I := 99;

Will cause a compile error saying "left-side cannot be assigned to". This is also because Delphi considers T.Rec to be a local copy of the internal record, not the record itself.