[System][@GetMem]
[CLRClasses][Marshal.AllocHGlobal]
[MemDS][TMemDataSet.AllocRecordBuffer]
[Db][TDataSet.SetBufListSize]
The example is of course no real life code, but it is similar to the real life code. The real life code is a TVirtualTable and a TDataSource on a TDataModule with the following conditions (without one of them it won't repeat):
- TDataSource is defined in the .dfm after the TVirtualTable
- the TVirtualTable won't be opened at runtime (either by streaming or by code)
- the TVirtualTable has data stored in the .dfm
In order to make the leaks disappear you can open the TVirtualTable or inherited TVirtualTable and call "SetBufListSize(0);" in the destructor. This bug very likely does also happen with other dataset's using MemDS.
Code: Select all
program MemDSVTLeak;
{$APPTYPE CONSOLE}
uses
FastMM4,
Classes,
DB,
VirtualTable;
{
The memory leak disappears if you either define DISAPPEAR1
or DISAPPEAR2. This are no workarounds - they just show the
root of the problem!
}
{.$DEFINE DISAPPEAR1}
{.$DEFINE DISAPPEAR2}
{$IFDEF DISAPPEAR1}
type
TVirtualTable = class(VirtualTable.TVirtualTable)
public
destructor Destroy; override;
end;
destructor TVirtualTable.Destroy;
begin
SetBufListSize(0);
inherited Destroy;
end;
{$ENDIF DISAPPEAR1}
const
DataArray: array [0..25] of Byte =
(2, 0, 1, 0, 2, 0, 73, 68, 3, 0, 0, 0, 0, 0, 1, 0,
0, 0, 4, 0, 0, 0, 1, 0, 0, 0);
var
MS: TMemoryStream;
vt: TVirtualTable;
ds: TDataSource;
begin
vt := TVirtualTable.Create(nil);
try
vt.FieldDefs.Add('ID', ftInteger);
MS := TMemoryStream.Create;
try
MS.Write(DataArray, Length(DataArray));
vt.LoadFromStream(MS, True);
{$IFDEF DISAPPEAR2}
vt.Open;
{$ENDIF DISAPPEAR2}
finally
MS.Free;
end;
ds := TDataSource.Create(nil);
try
ds.DataSet := vt;
finally
ds.Free;
end;
finally
vt.Free;
end;
end.