I have an application that contains a ClientDataSet connected in a DataSetProvider that is connected in an TIBQuery (Delphi 6).
I run several queries and after each of them I run the EmptyDataSet, Close, and Free methods.
For example:
procedure TAggregator.Load(ASql: string); begin try FQry.SQL.Text := ASql; FCds.SetProvider(FDsp); FCds.Open; FCds.EmptyDataSet; FCds.Close; except on e: Exception do raise e; end; end; This is the two files from my minimal app sample to reproduce the problem:
program CdsConsumptionTest; {$APPTYPE CONSOLE} uses SysUtils, Classes, IBDatabase, uAggregator in 'uAggregator.pas'; var database: TIBDatabase; transaction: TIBTransaction; aggregator: TAggregator; tables: TStringList; index: integer; begin try try database := TIBDatabase.Create(nil); transaction := TIBTransaction.Create(nil); try database.DefaultTransaction := transaction; database.Params.Values['user_name'] := 'SYSDBA'; database.Params.Values['password'] := 'masterkey'; database.SQLDialect := 3; database.LoginPrompt := false; database.DatabaseName := 'C:\bases\17011\BASE.GDB'; tables := TStringList.Create; aggregator := TAggregator.Create(database); try database.GetTableNames(tables); Writeln('Connection successful!'); Write('Press ENTER to continue ...'); // After that you can see the memory being increased and no longer released Readln; for index := 0 to pred(tables.Count) do begin aggregator.Load('select * from ' + tables[index]); end; finally tables.Free; aggregator.Free; end; finally database.Free; transaction.Free; end; except on e:Exception do begin Writeln(''); Writeln('ERROR! ' + e.Message); Writeln(''); end; end; finally Write('Process completed! Press ENTER to exit ...'); Readln; end; end. and...
unit uAggregator; interface uses IBQuery, DBClient, Provider, IBDatabase, SysUtils; type TAggregator = class private FQry: TIBQuery; FCds: TClientDataSet; FDsp: TDataSetProvider; public constructor Create(AIBDatabase: TIBDatabase); reintroduce; destructor Destroy; override; public procedure Load(ASql: string); end; implementation { TAgregador } constructor TAggregator.Create(AIBDatabase: TIBDatabase); begin inherited Create; FQry := TIBQuery.Create(nil); FQry.Database := AIBDatabase; FDsp := TDataSetProvider.Create(nil); FDsp.DataSet := FQry; FCds := TClientDataSet.Create(nil); FCds.SetProvider(FDsp); FCds.PacketRecords := -1; end; destructor TAggregator.Destroy; begin FCds.Free; FDsp.Free; FQry.Free; inherited; end; procedure TAggregator.Load(ASql: string); begin try FQry.SQL.Text := ASql; FCds.SetProvider(FDsp); FCds.Open; FCds.EmptyDataSet; FCds.Close; except on e: Exception do raise e; end; end; end. When I start the app I see that a lot of memory is allocated.
After pressing ENTER to start the queries I see by the Windows Task Manager that the memory is being incremented and never released.
Until the process reaches the point where I need to press ENTER to terminate the application and until then the memory that was allocated (even after the Free of the ClientDataSet) is not released.
In this small example it does not prove to be a big problem.
But in my actual application this is being raised an Out Of Memory type exception.
How I can solve this problem?
EDIT
Testing with FastMM4 I received the following report:
That I do not understand.
