Page 1 of 1

Out of Memory with Blob Fields

Posted: Fri 20 Mar 2015 14:03
by Execute
Hi,

Using IBDAC 4.6.11 when I loop on a Query, the process memory usage grows until the close. The components uses defaults properties, the query is SELECT * FROM TABLE from a table with 4300 lines and a BLOB field that can contain up to 3Mb.

Same problem if I select only a INT field but with less impact.

Code: Select all

procedure TForm4.Button4Click(Sender: TObject);
begin
// 2 020K (in Windows process manager under Windows 7 32bits with Delphi XE3)
  IBCConnection1.Database := dbName.Text;
  IBCConnection1.Open;
  IBCQuery3.Open;
  while not IBCQuery3.Eof do
  begin
    IBCQuery3.Next;
  end;
  ShowMEssage('done1'); // 16 668K
  IBCQuery3.Close;
  ShowMEssage('done2'); // 6 564K
  IBCConnection1.Close;
  ShowMEssage('done3'); // 6 680K (?!)
end;
// 6 540K

Is that a known problem ?

Regards

Re: Out of Memory with Blob Fields

Posted: Tue 24 Mar 2015 09:54
by ViktorV
To decrease memory consumption when working with BLOB fields, you can set the DeferredBlobRead option of TIBCQuery to True.
DeferredBlobRead is used for fetching BLOB values when they are explicitly requested. You can find more information about the DeferredBlobRead option in the IBDAC documentation: http://www.devart.com/ibdac/docs/devart ... obread.htm

Re: Out of Memory with Blob Fields

Posted: Tue 24 Mar 2015 10:22
by Execute
ok, but there still a problem.

I've just tried with last release 5.4 under Delphi XE7 and Windows 8.1

Code: Select all

procedure TForm1.Button1Click(Sender: TObject);
begin
  IBCQuery1.SQL.Text := 'SELECT COUNT(*) FROM MYTABLE';
  IBCQuery1.Execute;
  ProgressBar1.Max := IBCQuery1.Fields[0].AsInteger;
  ProgressBar1.Step := 1;
  ProgressBar1.Position := 0;
  IBCQuery1.SQL.Text := 'SELECT * FROM MYTABLE';
  IBCQuery1.Execute;
  while not IBCQuery1.Eof do
  begin
    ProgressBar1.StepIt;
    Application.ProcessMessages;
    IBCQuery1.Next;
  end;
  ShowMessage('Done1');
  IBCQuery1.Close;
  ShowMessage('Done2');
end;
the memory consumption still growing until the close without any memory leak.
In my case I went to an Out of Memory error before the end.

DeferredBlobRead partially resolve the problem, but there still a abnormal memory consumption when I do access the blob stream

Code: Select all

procedure TForm1.Button1Click(Sender: TObject);
var
  blob: TField;
  stream: TStream;
begin
  IBCQuery1.SQL.Text := 'SELECT COUNT(*) FROM MYTABLE';
  IBCQuery1.Execute;
  ProgressBar1.Max := IBCQuery1.Fields[0].AsInteger;
  ProgressBar1.Step := 1;
  ProgressBar1.Position := 0;
  IBCQuery1.SQL.Text := 'SELECT * FROM MYTABLE';
  IBCQuery1.Execute;

  blob := IBCQuery1.FieldByName('MYBLOB');

  while not IBCQuery1.Eof do
  begin
    ProgressBar1.StepIt;
    Application.ProcessMessages;

    stream := IBCQuery1.CreateBlobStream(blob, TBlobStreamMode.bmRead);
    AllocConsole;
    WriteLn(Stream.Size); // without this, the stream seems to do nothing
    stream.Free;

    IBCQuery1.Next;
  end;
  ShowMessage('Done1');
  IBCQuery1.Close;
  ShowMessage('Done2');
end;
you probably have a kind of garbage collector for Blob streams that avoid memory leaks after the close, but I think that you should explicitly release things before that.

Regards

Re: Out of Memory with Blob Fields

Posted: Tue 24 Mar 2015 13:41
by ViktorV
You can also decrease memory consumption when reading records using the UniDirectional mode, that is designed for memory saving by unidirectional navigation through records. See more details about the UniDirectional mode in the IBDAC documentation: http://www.devart.com/ibdac/docs/devart ... tional.htm