1

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:

FastMM4 Report

That I do not understand.

6
  • 2
    If you don't have it already, get FastMM4 (github.com/pleriche/FastMM4), and use it in you app with FullDebugMode set to true. This should give you a better idea that TaskMan will of any memory your app is using and not releasing. Commented May 30, 2018 at 21:05
  • 1
    The concept of try/finally is to create before entering the try part. Commented May 30, 2018 at 21:29
  • 3
    Task Manager is not a reliable way to test memory use in your application. Also, freeing a component does not necessarily result in the memory being returned to the OS; the Delphi memory manager does not release it, as it presumes you're just going to use it again. Use a better means of evaluating memory use, as @MartynA suggests. (Also, if you'r'e concerned about memory use, you probably shouldn't be using an in-memory dataset in the firs t place. TClientDataset is designed to hold a reasonable amount of data, not a huge dataset.) Commented May 30, 2018 at 22:47
  • @MartynA, I tried with FastMM4, I used the FullDebugMode directive, but I could not understand the report it generated. Commented Jun 4, 2018 at 12:45
  • 1
    Generate detailed map file and fastmm will give more stack information. Commented Jun 4, 2018 at 18:15

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.