Page 1 of 1

Memory Leak at DriverManager.GetConnection

Posted: 18.05.2011, 18:52
by JavaPauloMG
Hi Friends,

I have a trouble when i user this statement

"fConnection := DriverManager.GetConnection('zdbc:' + protocol + ':' + '//' + hostname + '/' + database + '?username=' + user + ';password=' + password);"

when i finalize program, the eurekalog, show me a error, the object still in memory, i try many ways to destroy, this object, but for example i use

"freeandnil(fConnection)"

The complier give a acessvilolation, i don't know what i can do to solve this problem... somebody can help me?

Thanks.

P.S: Sorry for my bad english, i'm from Brazil.

Posted: 18.05.2011, 19:26
by Dali
What I see is a call to inherited at the beginning of the destructor. Maybe putting that call at the end will solve your issue.

Posted: 18.05.2011, 19:51
by JavaPauloMG
I modify, but the error persist, i search and see the zdbc api, as based in interfaces, but the destroy don't work in interfaced objects, but i dont found the best way to free this memory, and when i work for some time the O.S have more slow, and the memory used has up.

But thanks my friend for the awser... ;-)

Posted: 18.05.2011, 23:56
by trupka
JavaPauloMG,
can you create some example so I can reproduce the problem?
I've been using Zeos with EL and FastMM for some time and never encountered
anything similar...

Posted: 20.05.2011, 13:56
by JavaPauloMG
Hi my friend, this is de code, when i destroy de object using the command "freeandnil", the system give a error, if somebody can help me, thanks to all.

Code: Select all

{*
  @author João Paulo da Silva Simões
  @version 0.1 - 2011/04/27
}

unit EntityManagerFirebird;

interface

uses
  DpaEntity, EntityManager, DpaField, ZConnection, ZDbcIntfs, Dialogs;

type
  TEntityManagerFirebird = class(TEntityManager)

  private
    { Private declarations }

    {*
    }
    fConnection : IZConnection;

    {*
    }
    function getSelectPreparedStatement(entity : TDpaEntity) : IZPreparedStatement;

    {*
    }
    function getSelectKeyFieldsPreparedStatement(entity : TDpaEntity) : IZPreparedStatement;

    {*
    }
    function getInsertPreparedStatement(entity : TDpaEntity) : IZPreparedStatement;

    {*
    }
    function getUpdatePreparedStatement(entity : TDpaEntity) : IZPreparedStatement;

    {*
    }
    function getDeletePreparedStatement(entity : TDpaEntity) : IZPreparedStatement;

    {*
    }
    function getFields(dpaFieldArray : TDpaFieldArray) : String;

    {*
    }
    function getFieldsParams(dpaFieldArray : TDpaFieldArray) : String;

    {*
    }
    function getFieldsParamsAnd(dpaFieldArray : TDpaFieldArray) : String;    

    {*
    }
    procedure setParamsPreparedStatement(var preparedStatement : IZPreparedStatement; dpaFieldArrays : array of TDpaFieldArray); overload;

  protected
  { Protected declarations }

  public
    { Public declarations }

    {*
    }
    constructor create(protocol : String; hostname : String; database : String; user : String; password : String; dialect : String);

    {*
    }
    destructor destroy(); override;

    {*
    }
    procedure close(); override;

    {*
    }
    procedure beginTransaction(); override;

    {*
    }
    procedure commitTransaction(); override;

    {*
    }
    procedure rollbackTransaction(); override;

    {*
    }
    procedure persist(entity : TDpaEntity); override;

    {*
    }
    procedure remove(entity : TDpaEntity); override;

    {*
    }
    function find(entity : TDpaEntity) : TDpaEntity; override;

  published
    { Published declarations }

end;

implementation

uses SysUtils, StrUtils;

{ TEntityManagerFirebird }

constructor TEntityManagerFirebird.create(protocol : String; hostname : String; database : String; user : String; password : String; dialect : String);
begin
  fConnection := DriverManager.GetConnection('zdbc:' + protocol + ':' + '//' + hostname + '/' + database + '?username=' + user + ';password=' + password);
  fConnection.SetAutoCommit(True);
  fConnection.SetTransactionIsolation(tiReadCommitted);
end;

destructor TEntityManagerFirebird.destroy;
begin
  inherited;
  FreeAndNil(fConnection);
end;

procedure TEntityManagerFirebird.close;
begin
  fConnection.Close();
end;

procedure TEntityManagerFirebird.beginTransaction;
begin
  fConnection.SetAutoCommit(False);
end;

procedure TEntityManagerFirebird.commitTransaction;
begin
  fConnection.Commit;
  fConnection.SetAutoCommit(True);
end;

procedure TEntityManagerFirebird.rollbackTransaction;
begin
  fConnection.Rollback;
  fConnection.SetAutoCommit(True);
end;

procedure TEntityManagerFirebird.persist(entity: TDpaEntity);
var
  fPreparedStatement : IZPreparedStatement;
  fResultSet         : IZResultSet;
begin

  fPreparedStatement := getSelectKeyFieldsPreparedStatement(entity);

  fPreparedStatement.ExecutePrepared();

  fResultSet := fPreparedStatement.ExecuteQueryPrepared();

  if (not fResultSet.Next()) then begin

    fPreparedStatement := getInsertPreparedStatement(entity);

  end else begin

    fPreparedStatement := getUpdatePreparedStatement(entity);

  end;

  fPreparedStatement.ExecutePrepared();  

end;

procedure TEntityManagerFirebird.remove(entity: TDpaEntity);
var
  fPreparedStatement : IZPreparedStatement;
  fResultSet         : IZResultSet;
begin

  fPreparedStatement := getDeletePreparedStatement(entity);

  fPreparedStatement.ExecutePrepared();

end;

function TEntityManagerFirebird.find(entity: TDpaEntity): TDpaEntity;
begin

end;

function TEntityManagerFirebird.getFields(dpaFieldArray: TDpaFieldArray): String;
var
  i         : Integer;
  keyFields : String;
begin

  keyFields := '';

  for i := 0 to Length(dpaFieldArray) - 1 do begin

    keyFields := keyFields + TDpaField(dpaFieldArray[i]).columnName + ', ';

  end;

  if (keyFields = '') then begin

    keyFields := '*';

  end else begin

    keyFields := Copy(keyFields, 1, Length(keyFields) - 2);

  end;

  Result := keyFields;

end;

function TEntityManagerFirebird.getFieldsParams(dpaFieldArray: TDpaFieldArray): String;
var
  i         : Integer;
  keyFields : String;
begin

  keyFields := '';

  for i := 0 to Length(dpaFieldArray) - 1 do begin

    keyFields := keyFields + TDpaField(dpaFieldArray[i]).columnName + '=?, ';

  end;

  if (keyFields = '') then begin

    keyFields := '*';

  end else begin

    keyFields := Copy(keyFields, 1, Length(keyFields) - 2);

  end;

  Result := keyFields;

end;

function TEntityManagerFirebird.getFieldsParamsAnd(dpaFieldArray: TDpaFieldArray): String;
var
  i         : Integer;
  keyFields : String;
begin

  keyFields := '';

  for i := 0 to Length(dpaFieldArray) - 1 do begin

    keyFields := keyFields + TDpaField(dpaFieldArray[i]).columnName + '=? and ';

  end;

  if (keyFields = '') then begin

    keyFields := '*';

  end else begin

    keyFields := Copy(keyFields, 1, Length(keyFields) - 5);

  end;

  Result := keyFields;

end;

function TEntityManagerFirebird.getSelectPreparedStatement(entity: TDpaEntity): IZPreparedStatement;
var
  fDpaFieldArray     : TDpaFieldArray;
  fPreparedStatement : IZPreparedStatement;
begin

  fDpaFieldArray     := entity.getFields();

  fPreparedStatement := fConnection.PrepareStatement('select ' + getFields(fDpaFieldArray) + ' from ' + entity.getTableName() + ' where ' + getFieldsParamsAnd(fDpaFieldArray));
  setParamsPreparedStatement(fPreparedStatement, [fDpaFieldArray]);

  Result := fPreparedStatement;

end;

function TEntityManagerFirebird.getSelectKeyFieldsPreparedStatement(entity: TDpaEntity): IZPreparedStatement;
var
  fDpaKeyFieldArray  : TDpaFieldArray;
  fPreparedStatement : IZPreparedStatement;
begin

  fDpaKeyFieldArray  := entity.getKeyFields();

  fPreparedStatement := fConnection.PrepareStatement('select ' + getFields(fDpaKeyFieldArray) + ' from ' + entity.getTableName() + ' where ' + getFieldsParamsAnd(fDpaKeyFieldArray));
  setParamsPreparedStatement(fPreparedStatement, [fDpaKeyFieldArray]);

  Result := fPreparedStatement;

end;

function TEntityManagerFirebird.getInsertPreparedStatement(entity: TDpaEntity): IZPreparedStatement;
var
  fDpaFieldArray     : TDpaFieldArray;
  fPreparedStatement : IZPreparedStatement;
begin

  fDpaFieldArray     := entity.getFields();

  fPreparedStatement := fConnection.PrepareStatement('insert into ' + entity.getTableName() + ' ' +  '(' + getFields(fDpaFieldArray) + ')' + ' ' + 'values' + '(' + Copy(DupeString('?, ', Length(fDpaFieldArray)), 1, Length(DupeString('?, ', Length(fDpaFieldArray))) - 2)  + ')');
  setParamsPreparedStatement(fPreparedStatement, [fDpaFieldArray]);

  Result := fPreparedStatement;

end;

function TEntityManagerFirebird.getUpdatePreparedStatement(entity: TDpaEntity): IZPreparedStatement;
var
  fDpaFieldArray     : TDpaFieldArray;
  fDpaKeyFieldArray  : TDpaFieldArray;
  fPreparedStatement : IZPreparedStatement;
begin

  fDpaFieldArray     := entity.getFields();
  fDpaKeyFieldArray  := entity.getKeyFields();  

  fPreparedStatement := fConnection.PrepareStatement('update ' + entity.getTableName() + ' ' + 'set' + ' ' + getFieldsParams(fDpaFieldArray) + ' ' + 'where' + ' ' + getFieldsParamsAnd(fDpaKeyFieldArray));
  setParamsPreparedStatement(fPreparedStatement, [fDpaFieldArray, fDpaKeyFieldArray]);

  Result := fPreparedStatement;

end;

function TEntityManagerFirebird.getDeletePreparedStatement(entity: TDpaEntity): IZPreparedStatement;
var
  fDpaKeyFieldArray  : TDpaFieldArray;
  fPreparedStatement : IZPreparedStatement;
begin

  fDpaKeyFieldArray  := entity.getKeyFields();

  fPreparedStatement := fConnection.PrepareStatement('delete from ' + entity.getTableName() + ' where ' + getFieldsParamsAnd(fDpaKeyFieldArray));
  setParamsPreparedStatement(fPreparedStatement, [fDpaKeyFieldArray]);

  Result := fPreparedStatement;

end;

procedure TEntityManagerFirebird.setParamsPreparedStatement(var preparedStatement : IZPreparedStatement; dpaFieldArrays : array of TDpaFieldArray);
var
  i, j       : Integer;
  paramCount : Integer;
begin

  paramCount := 0;

  for i := 0 to Length(dpaFieldArrays) - 1 do begin

    for j := 0 to Length(dpaFieldArrays[i]) - 1 do begin

      paramCount := paramCount + 1;

      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldShortint)) then begin

        preparedStatement.SetShort(paramCount, TDpaFieldShortint (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldSmallint)) then begin

        preparedStatement.SetShort(paramCount, TDpaFieldSmallint (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldInteger )) then begin

        preparedStatement.SetInt  (paramCount, TDpaFieldInteger  (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldLongint )) then begin

        preparedStatement.SetLong (paramCount, TDpaFieldLongint  (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldByte    )) then begin

        preparedStatement.SetByte (paramCount, TDpaFieldByte     (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldWord    )) then begin

        preparedStatement.SetInt  (paramCount, TDpaFieldWord     (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldLongWord)) then begin

        preparedStatement.SetLong  (paramCount, TDpaFieldLongWord(TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldString  )) then begin

        preparedStatement.SetString(paramCount, TDpaFieldString  (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldClob    )) then begin

        preparedStatement.SetString(paramCount, TDpaFieldClob    (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end;

    end;

  end;

end;

end.

Posted: 20.05.2011, 15:00
by trupka
you can't (and don't need to) freeAndNil interfaced object because they are reference counted and automaticaly freed when not needed. IMO, it is sufficient to:

Code: Select all

destructor TEntityManagerFirebird.destroy;
begin
  fConnection.CLose;
  fConnection := nil;
  inherited;
end;
I tried to generate memory leaks (see sample project in attach) without success. This could mean that the leak is actually in some other part of the code.
JavaPauloMG, can you test my sample?

Posted: 24.05.2011, 12:58
by JavaPauloMG
Hi my friend, i have test following the way you show me, and the memory leak only have ocorrured when i execute the statment, but when i execute de statment "remove" the error don't ocorrurs:

Code: Select all

procedure TEntityManagerFirebird.persist(entity: TDpaEntity); 
var 
  fPreparedStatement : IZPreparedStatement; 
  fResultSet         : IZResultSet; 
begin 

  fPreparedStatement := getSelectKeyFieldsPreparedStatement(entity); 

  fPreparedStatement.ExecutePrepared(); 

  fResultSet := fPreparedStatement.ExecuteQueryPrepared(); 

  if (not fResultSet.Next()) then begin 

    fPreparedStatement := getInsertPreparedStatement(entity); 

  end else begin 

    fPreparedStatement := getUpdatePreparedStatement(entity); 

  end; 

  fPreparedStatement.ExecutePrepared();  

end;
I now this is the sample code of memory leak:

Code: Select all

{*
  @author João Paulo da Silva Simões
  @version 0.1 - 2011/04/27
}

unit EntityManagerFirebird;

interface

uses
  DpaEntity, EntityManager, DpaField, ZConnection, ZDbcIntfs, Dialogs;

type
  TEntityManagerFirebird = class(TEntityManager)

  private
    { Private declarations }

    {*
    }
    fConnection : IZConnection;

    {*
    }
    function getSelectPreparedStatement(entity : TDpaEntity) : IZPreparedStatement;

    {*
    }
    function getSelectKeyFieldsPreparedStatement(entity : TDpaEntity) : IZPreparedStatement;

    {*
    }
    function getInsertPreparedStatement(entity : TDpaEntity) : IZPreparedStatement;

    {*
    }
    function getUpdatePreparedStatement(entity : TDpaEntity) : IZPreparedStatement;

    {*
    }
    function getDeletePreparedStatement(entity : TDpaEntity) : IZPreparedStatement;

    {*
    }
    function getFields(dpaFieldArray : TDpaFieldArray) : String;

    {*
    }
    function getFieldsParams(dpaFieldArray : TDpaFieldArray) : String;

    {*
    }
    function getFieldsParamsAnd(dpaFieldArray : TDpaFieldArray) : String;    

    {*
    }
    procedure setParamsPreparedStatement(var preparedStatement : IZPreparedStatement; dpaFieldArrays : array of TDpaFieldArray); overload;

  protected
  { Protected declarations }

  public
    { Public declarations }

    {*
    }
    constructor create(protocol : String; hostname : String; database : String; user : String; password : String; dialect : String);

    {*
    }
    destructor destroy(); override;

    {*
    }
    procedure close(); override;

    {*
    }
    procedure beginTransaction(); override;

    {*
    }
    procedure commitTransaction(); override;

    {*
    }
    procedure rollbackTransaction(); override;

    {*
    }
    procedure persist(entity : TDpaEntity); override;

    {*
    }
    procedure remove(entity : TDpaEntity); override;

    {*
    }
    function find(entity : TDpaEntity) : TDpaEntity; override;

  published
    { Published declarations }

end;

implementation

uses SysUtils, StrUtils;

{ TEntityManagerFirebird }

constructor TEntityManagerFirebird.create(protocol : String; hostname : String; database : String; user : String; password : String; dialect : String);
begin
  fConnection := DriverManager.GetConnection('zdbc:' + protocol + ':' + '//' + hostname + '/' + database + '?username=' + user + ';password=' + password);
  fConnection.SetAutoCommit(True);
  fConnection.SetTransactionIsolation(tiReadCommitted);
end;

destructor TEntityManagerFirebird.destroy;
begin
  fConnection.CLose; 
  fConnection := nil; 
  inherited;
end;

procedure TEntityManagerFirebird.close;
begin
  fConnection.Close();
end;

procedure TEntityManagerFirebird.beginTransaction;
begin
  fConnection.SetAutoCommit(False);
end;

procedure TEntityManagerFirebird.commitTransaction;
begin
  fConnection.Commit;
  fConnection.SetAutoCommit(True);
end;

procedure TEntityManagerFirebird.rollbackTransaction;
begin
  fConnection.Rollback;
  fConnection.SetAutoCommit(True);
end;

procedure TEntityManagerFirebird.persist(entity: TDpaEntity);
var
  fPreparedStatement : IZPreparedStatement;
  fResultSet         : IZResultSet;
begin

  fPreparedStatement := getSelectKeyFieldsPreparedStatement(entity);

  fPreparedStatement.ExecutePrepared();

  fResultSet := fPreparedStatement.ExecuteQueryPrepared();

  if (not fResultSet.Next()) then begin

    fPreparedStatement := getInsertPreparedStatement(entity);

  end else begin

    fPreparedStatement := getUpdatePreparedStatement(entity);

  end;

  fPreparedStatement.ExecutePrepared();  

end;

procedure TEntityManagerFirebird.remove(entity: TDpaEntity);
var
  fPreparedStatement : IZPreparedStatement;
  fResultSet         : IZResultSet;
begin

  fPreparedStatement := getDeletePreparedStatement(entity);

  fPreparedStatement.ExecutePrepared();

end;

function TEntityManagerFirebird.find(entity: TDpaEntity): TDpaEntity;
begin

end;

function TEntityManagerFirebird.getFields(dpaFieldArray: TDpaFieldArray): String;
var
  i         : Integer;
  keyFields : String;
begin

  keyFields := '';

  for i := 0 to Length(dpaFieldArray) - 1 do begin

    keyFields := keyFields + TDpaField(dpaFieldArray[i]).columnName + ', ';

  end;

  if (keyFields = '') then begin

    keyFields := '*';

  end else begin

    keyFields := Copy(keyFields, 1, Length(keyFields) - 2);

  end;

  Result := keyFields;

end;

function TEntityManagerFirebird.getFieldsParams(dpaFieldArray: TDpaFieldArray): String;
var
  i         : Integer;
  keyFields : String;
begin

  keyFields := '';

  for i := 0 to Length(dpaFieldArray) - 1 do begin

    keyFields := keyFields + TDpaField(dpaFieldArray[i]).columnName + '=?, ';

  end;

  if (keyFields = '') then begin

    keyFields := '*';

  end else begin

    keyFields := Copy(keyFields, 1, Length(keyFields) - 2);

  end;

  Result := keyFields;

end;

function TEntityManagerFirebird.getFieldsParamsAnd(dpaFieldArray: TDpaFieldArray): String;
var
  i         : Integer;
  keyFields : String;
begin

  keyFields := '';

  for i := 0 to Length(dpaFieldArray) - 1 do begin

    keyFields := keyFields + TDpaField(dpaFieldArray[i]).columnName + '=? and ';

  end;

  if (keyFields = '') then begin

    keyFields := '*';

  end else begin

    keyFields := Copy(keyFields, 1, Length(keyFields) - 5);

  end;

  Result := keyFields;

end;

function TEntityManagerFirebird.getSelectPreparedStatement(entity: TDpaEntity): IZPreparedStatement;
var
  fDpaFieldArray     : TDpaFieldArray;
  fPreparedStatement : IZPreparedStatement;
begin

  fDpaFieldArray     := entity.getFields();

  fPreparedStatement := fConnection.PrepareStatement('select ' + getFields(fDpaFieldArray) + ' from ' + entity.getTableName() + ' where ' + getFieldsParamsAnd(fDpaFieldArray));
  setParamsPreparedStatement(fPreparedStatement, [fDpaFieldArray]);

  Result := fPreparedStatement;

end;

function TEntityManagerFirebird.getSelectKeyFieldsPreparedStatement(entity: TDpaEntity): IZPreparedStatement;
var
  fDpaKeyFieldArray  : TDpaFieldArray;
  fPreparedStatement : IZPreparedStatement;
begin

  fDpaKeyFieldArray  := entity.getKeyFields();

  fPreparedStatement := fConnection.PrepareStatement('select ' + getFields(fDpaKeyFieldArray) + ' from ' + entity.getTableName() + ' where ' + getFieldsParamsAnd(fDpaKeyFieldArray));
  setParamsPreparedStatement(fPreparedStatement, [fDpaKeyFieldArray]);

  Result := fPreparedStatement;

end;

function TEntityManagerFirebird.getInsertPreparedStatement(entity: TDpaEntity): IZPreparedStatement;
var
  fDpaFieldArray     : TDpaFieldArray;
  fPreparedStatement : IZPreparedStatement;
begin

  fDpaFieldArray     := entity.getFields();

  fPreparedStatement := fConnection.PrepareStatement('insert into ' + entity.getTableName() + ' ' +  '(' + getFields(fDpaFieldArray) + ')' + ' ' + 'values' + '(' + Copy(DupeString('?, ', Length(fDpaFieldArray)), 1, Length(DupeString('?, ', Length(fDpaFieldArray))) - 2)  + ')');
  setParamsPreparedStatement(fPreparedStatement, [fDpaFieldArray]);

  Result := fPreparedStatement;

end;

function TEntityManagerFirebird.getUpdatePreparedStatement(entity: TDpaEntity): IZPreparedStatement;
var
  fDpaFieldArray     : TDpaFieldArray;
  fDpaKeyFieldArray  : TDpaFieldArray;
  fPreparedStatement : IZPreparedStatement;
begin

  fDpaFieldArray     := entity.getFields();
  fDpaKeyFieldArray  := entity.getKeyFields();  

  fPreparedStatement := fConnection.PrepareStatement('update ' + entity.getTableName() + ' ' + 'set' + ' ' + getFieldsParams(fDpaFieldArray) + ' ' + 'where' + ' ' + getFieldsParamsAnd(fDpaKeyFieldArray));
  setParamsPreparedStatement(fPreparedStatement, [fDpaFieldArray, fDpaKeyFieldArray]);

  Result := fPreparedStatement;

end;

function TEntityManagerFirebird.getDeletePreparedStatement(entity: TDpaEntity): IZPreparedStatement;
var
  fDpaKeyFieldArray  : TDpaFieldArray;
  fPreparedStatement : IZPreparedStatement;
begin

  fDpaKeyFieldArray  := entity.getKeyFields();

  fPreparedStatement := fConnection.PrepareStatement('delete from ' + entity.getTableName() + ' where ' + getFieldsParamsAnd(fDpaKeyFieldArray));
  setParamsPreparedStatement(fPreparedStatement, [fDpaKeyFieldArray]);

  Result := fPreparedStatement;

end;

procedure TEntityManagerFirebird.setParamsPreparedStatement(var preparedStatement : IZPreparedStatement; dpaFieldArrays : array of TDpaFieldArray);
var
  i, j       : Integer;
  paramCount : Integer;
begin

  paramCount := 0;

  for i := 0 to Length(dpaFieldArrays) - 1 do begin

    for j := 0 to Length(dpaFieldArrays[i]) - 1 do begin

      paramCount := paramCount + 1;

      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldShortint)) then begin

        preparedStatement.SetShort(paramCount, TDpaFieldShortint (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldSmallint)) then begin

        preparedStatement.SetShort(paramCount, TDpaFieldSmallint (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldInteger )) then begin

        preparedStatement.SetInt  (paramCount, TDpaFieldInteger  (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldLongint )) then begin

        preparedStatement.SetLong (paramCount, TDpaFieldLongint  (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldByte    )) then begin

        preparedStatement.SetByte (paramCount, TDpaFieldByte     (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldWord    )) then begin

        preparedStatement.SetInt  (paramCount, TDpaFieldWord     (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldLongWord)) then begin

        preparedStatement.SetLong  (paramCount, TDpaFieldLongWord(TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldString  )) then begin

        preparedStatement.SetString(paramCount, TDpaFieldString  (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end else
      if (TDpaField(TDpaFieldArray(dpaFieldArrays[i])[j]).InheritsFrom(TDpaFieldClob    )) then begin

        preparedStatement.SetString(paramCount, TDpaFieldClob    (TDpaFieldArray(dpaFieldArrays[i])[j]).value);

      end;

    end;

  end;

end;

end.

Code: Select all

{*
  @author João Paulo da Silva Simões
  @version 0.1 - 2011/05/05
}

unit DpaField;

interface

type
  TDpaField = class(TObject)

  private
   { Private declarations }

    fColumnName : String;
    fKey        : Boolean;

    function getColumnName() : String;
    function getKey() : Boolean;

    procedure setColumnName(value : String);
    procedure setKey(value : Boolean);

  protected
   { Protected declarations }

  public
   { Public declarations }

    constructor Create(columnName : String; key : Boolean);
    destructor Destroy; override;

    property columnName : String  read getColumnName write setColumnName;
    property key        : Boolean read getKey        write setKey;

  published
   { Published declarations }

  end;

type
  TDpaFieldArray = array of TDpaField;

type
  TDpaFieldShortint = class(TDpaField)

  private
   { Private declarations }

    fValue : Shortint;

    function getValue() : Shortint;

    procedure setValue(value : Shortint);

  protected
   { Protected declarations }

  public
   { Public declarations }

    constructor Create(columnName : String; key : Boolean); reintroduce;
    destructor Destroy; override;

    property value : Shortint read getValue write setValue;

  published
   { Published declarations }

  end;

type
  TDpaFieldSmallint = class(TDpaField)

  private
   { Private declarations }

    fValue : Smallint;

    function getValue() : Smallint;

    procedure setValue(value : Smallint);

  protected
   { Protected declarations }

  public
   { Public declarations }

    constructor Create(columnName : String; key : Boolean); reintroduce;
    destructor Destroy; override;

    property value : Smallint read getValue write setValue;

  published
   { Published declarations }

  end;

type
  TDpaFieldInteger = class(TDpaField)

  private
   { Private declarations }

    fValue : Integer;

    function getValue() : Integer;

    procedure setValue(value : Integer);

  protected
   { Protected declarations }

  public
   { Public declarations }

    constructor Create(columnName : String; key : Boolean); reintroduce; 
    destructor Destroy; override;

    property value : Integer read getValue write setValue;

  published
   { Published declarations }

  end;

type
  TDpaFieldLongint = class(TDpaField)

  private
   { Private declarations }

    fValue : Longint;

    function getValue() : Longint;

    procedure setValue(value : Longint);

  protected
   { Protected declarations }

  public
   { Public declarations }

    constructor Create(columnName : String; key : Boolean); reintroduce;
    destructor Destroy; override;

    property value : Longint read getValue write setValue;

  published
   { Published declarations }

  end;

type
  TDpaFieldByte = class(TDpaField)

  private
   { Private declarations }

    fValue : Byte;

    function getValue() : Byte;

    procedure setValue(value : Byte);

  protected
   { Protected declarations }

  public
   { Public declarations }

    constructor Create(columnName : String; key : Boolean); reintroduce;
    destructor Destroy; override;

    property value : Byte read getValue write setValue;

  published
   { Published declarations }

  end;

type
  TDpaFieldWord = class(TDpaField)

  private
   { Private declarations }

    fValue : Word;

    function getValue() : Word;

    procedure setValue(value : Word);

  protected
   { Protected declarations }

  public
   { Public declarations }

    constructor Create(columnName : String; key : Boolean); reintroduce;
    destructor Destroy; override;

    property value : Word read getValue write setValue;

  published
   { Published declarations }

  end;

type
  TDpaFieldLongWord = class(TDpaField)

  private
   { Private declarations }

    fValue : LongWord;

    function getValue() : LongWord;

    procedure setValue(value : LongWord);

  protected
   { Protected declarations }

  public
   { Public declarations }

    constructor Create(columnName : String; key : Boolean); reintroduce;
    destructor Destroy; override;

    property value : LongWord read getValue write setValue;

  published
   { Published declarations }

  end;

type
  TDpaFieldString = class(TDpaField)

  private
   { Private declarations }

    fValue : String;

    function getValue() : String;

    procedure setValue(value : String);

  protected
   { Protected declarations }

  public
   { Public declarations }

    constructor Create(columnName : String; key : Boolean); reintroduce;
    destructor Destroy; override;

    property value : String read getValue write setValue;

  published
   { Published declarations }

  end;

type
  TDpaFieldClob = class(TDpaField)

  private
   { Private declarations }

    fValue : WideString;

    function getValue() : WideString;

    procedure setValue(value : WideString);

  protected
   { Protected declarations }

  public
   { Public declarations }

    constructor Create(columnName : String; key : Boolean); reintroduce;
    destructor Destroy; override;

    property value : WideString read getValue write setValue;

  published
   { Published declarations }

  end;

implementation

{ TDpaField }

constructor TDpaField.Create(columnName : String; key : Boolean);
begin

  fColumnName := columnName;
  fKey        := key;

end;

destructor TDpaField.Destroy;
begin
  inherited;
  {}
end;

function TDpaField.getColumnName: String;
begin

  Result := fColumnName;

end;

function TDpaField.getKey: Boolean;
begin

  Result := fKey;

end;

procedure TDpaField.setColumnName(value: String);
begin

  fColumnName := value;

end;

procedure TDpaField.setKey(value: Boolean);
begin

  fKey := value;

end;

{ TDpaFieldInteger }

constructor TDpaFieldInteger.Create(columnName : String; key : Boolean);
begin
  inherited Create(columnName, key);

  fValue := 0;

end;

destructor TDpaFieldInteger.Destroy;
begin
  inherited;
  {}
end;

function TDpaFieldInteger.getValue: Integer;
begin

  Result := fValue;

end;

procedure TDpaFieldInteger.setValue(value: Integer);
begin

  fValue := value;

end;

{ TDpaFieldShortint }

constructor TDpaFieldShortint.Create(columnName : String; key : Boolean);
begin
  inherited Create(columnName, key);

  fValue := 0;

end;

destructor TDpaFieldShortint.Destroy;
begin
  inherited;
  {}
end;

function TDpaFieldShortint.getValue: Shortint;
begin

  Result := fValue;

end;

procedure TDpaFieldShortint.setValue(value: Shortint);
begin

  fValue := value;

end;

{ TDpaFieldSmallint }

constructor TDpaFieldSmallint.Create(columnName : String; key : Boolean);
begin
  inherited Create(columnName, key);

  fValue := 0;

end;

destructor TDpaFieldSmallint.Destroy;
begin
  inherited;
  {}
end;

function TDpaFieldSmallint.getValue: Smallint;
begin

  Result := fValue;

end;

procedure TDpaFieldSmallint.setValue(value: Smallint);
begin

  fValue := value;

end;

{ TDpaFieldLongint }

constructor TDpaFieldLongint.Create(columnName : String; key : Boolean);
begin
  inherited Create(columnName, key);

  fValue := 0;

end;

destructor TDpaFieldLongint.Destroy;
begin
  inherited;
  {}
end;

function TDpaFieldLongint.getValue: Longint;
begin

  fValue := 0;

end;

procedure TDpaFieldLongint.setValue(value: Integer);
begin

  fValue := value;

end;

{ TDpaFieldByte }

constructor TDpaFieldByte.Create(columnName : String; key : Boolean);
begin
  inherited Create(columnName, key);

  fValue := 0;

end;

destructor TDpaFieldByte.Destroy;
begin
  inherited;
  {}
end;

function TDpaFieldByte.getValue: Byte;
begin

  Result := fValue;

end;

procedure TDpaFieldByte.setValue(value: Byte);
begin

  fValue := value;

end;

{ TDpaFieldWord }

constructor TDpaFieldWord.Create(columnName : String; key : Boolean);
begin
  inherited Create(columnName, key);

  fValue := 0;

end;

destructor TDpaFieldWord.Destroy;
begin
  inherited;
  {}
end;

function TDpaFieldWord.getValue: Word;
begin

  Result := fValue;

end;

procedure TDpaFieldWord.setValue(value: Word);
begin

  fValue := value;

end;

{ TDpaFieldLongWord }

constructor TDpaFieldLongWord.Create(columnName : String; key : Boolean);
begin
  inherited Create(columnName, key);

  fValue := 0;

end;

destructor TDpaFieldLongWord.Destroy;
begin
  inherited;
  {}
end;

function TDpaFieldLongWord.getValue: LongWord;
begin

  Result := fValue;

end;

procedure TDpaFieldLongWord.setValue(value: LongWord);
begin

  fValue := value;

end;

{ TDpaFieldString }

constructor TDpaFieldString.Create(columnName : String; key : Boolean);
begin
  inherited Create(columnName, key);

  fValue := '';

end;

destructor TDpaFieldString.Destroy;
begin
  inherited;
  {}
end;

function TDpaFieldString.getValue: String;
begin

  Result := fValue;

end;

procedure TDpaFieldString.setValue(value: String);
begin

  fValue := value;

end;

{ TDpaFieldClob }

constructor TDpaFieldClob.Create(columnName : String; key : Boolean);
begin
  inherited Create(columnName, key);

  fValue := '';

end;

destructor TDpaFieldClob.Destroy;
begin
  inherited;
  {}
end;

function TDpaFieldClob.getValue: WideString;
begin

  Result := fValue;

end;

procedure TDpaFieldClob.setValue(value: WideString);
begin

  fValue := value;

end;

end.

Code: Select all

{*
  @author João Paulo da Silva Simões
  @version 0.1 - 2011/05/05
}

unit Tabela;

interface

uses
  DpaEntity, DpaField,
  SysUtils;

type
  TTabela = class(TDpaEntity)

  private
   { Private declarations }

    {*
    }
    fId    : TDpaFieldInteger;
    fNome  : TDpaFieldString ;
    fTexto : TDpaFieldClob   ;

    {*
    }
    function getId: Integer;
    function getNome: String;
    function getTexto: WideString;

    {*
    }
    procedure setId(value: Integer);
    procedure setNome(value: String);
    procedure setTexto(value: WideString);

  protected
   { Protected declarations }

  public
   { Public declarations }

    {*
    }
    constructor Create; 

    {*
    }
    destructor Destroy; override;

    {*
    }
    property id    : Integer    read getId    write setId   ;
    property nome  : String     read getNome  write setNome ;
    property texto : WideString read getTexto write setTexto;

    {*
    }
    function getTableName() : String; override;

    {*
    }
    function getFields() : TDpaFieldArray; override;

  published
   { Published declarations }

end;

implementation

uses TypInfo;

{ TTabela }

constructor TTabela.Create;
begin
  inherited;

  fId    := TDpaFieldInteger.Create('id'   , True );
  fNome  := TDpaFieldString .Create('nome' , False);
  fTexto := TDpaFieldClob   .Create('texto', False);

end;

destructor TTabela.Destroy;
begin
  inherited;

  FreeAndNil(fId   );
  FreeAndNil(fNome );
  FreeAndNil(fTexto);

end;

function TTabela.getFields: TDpaFieldArray;
var
  fDpaFieldArray : TDpaFieldArray;
begin

  SetLength(fDpaFieldArray, 3);

  fDpaFieldArray[0] := fId   ;
  fDpaFieldArray[1] := fNome ;
  fDpaFieldArray[2] := fTexto;

  Result := fDpaFieldArray;

end;

function TTabela.getId: Integer;
begin

  Result := fId.value;

end;

function TTabela.getNome: String;
begin

  Result := fNome.value;

end;

function TTabela.getTableName: String;
begin
  Result := 'Tabela'
end;

function TTabela.getTexto: WideString;
begin

  Result := fTexto.value;

end;

procedure TTabela.setId(value: Integer);
begin

  fId.value := value;

end;

procedure TTabela.setNome(value: String);
begin

  fNome.value := value;

end;

procedure TTabela.setTexto(value: WideString);
begin

  fTexto.value := value;

end;

end.
This is the event when the memory leaks ocorrur:

Code: Select all

procedure TForm1.btnTmpClick(Sender: TObject);
var
  entity                : TTabela;
  entityManagerFirebird : TEntityManagerFirebird;
begin

  entity := TTabela.Create();
  entityManagerFirebird := TEntityManagerFirebird.create('firebird-2.1', '127.0.0.1', 'C:\Desenvolvimento\OODelphiBasicImplementation\BANCO.FDB', 'SYSDBA', 'masterkey', '3');

  entityManagerFirebird.persist(entity);

  FreeAndNil(entity);
  FreeAndNil(entityManagerFirebird);

end;
This is the script i have use to test this simple application:

Code: Select all


/* Table: TABELA, Owner: SYSDBA */

CREATE TABLE "TABELA" 
(
  "ID"	 INTEGER NOT NULL,
  "NOME"	 VARCHAR(50),
  "TEXTO"	 BLOB SUB_TYPE TEXT SEGMENT SIZE 1,
CONSTRAINT "PK_TABELA" PRIMARY KEY ("ID")
);
I use, Delphi 7 Professional, and ZeosLib 6.6.6.

Thanks if you can help-me, to catch the memory leaks i use the EurekaLog Trial.

Posted: 24.05.2011, 14:30
by JavaPauloMG
I make some more tests, and the memory leaks only ocorrurs when the prepared statement, execute a select statement, the erro not ocorrurs, when are a update, insert, or delete statment.

Posted: 25.05.2011, 12:28
by JavaPauloMG
I discover the error, when i use de IZPreparedStatement, with a "select" command, the memory leak, ocorrurs, but when i use IZStatment, so make a "select" the memory leak don't ocorrurs, somebody can tell me if this is a correct behavior? or i use the wrong component to make a simple "select?"

This is the code when the memomy leaks ocorrurs :

Code: Select all

fPreparedStatement := fConnection.PrepareStatement('select ' + getFields(fDpaKeyFieldArray) + ' from ' + entity.getTableName() + ' where ' + getFieldsParamsAnd(fDpaKeyFieldArray));
I want to use the IZPreparedStatment, do make a "select" command, because this interface accept add params...

Posted: 26.05.2011, 14:00
by JavaPauloMG
It's me again, i discover my error, this a sample how the error occurs:

Code: Select all

procedure TForm1.btnTmpClick(Sender: TObject);
var
  fConnection        : IZConnection;
  fPreparedStatement : IZPreparedStatement;
begin

  fConnection        := DriverManager.GetConnection('zdbc:firebird-2.1://127.0.0.1/C:\Desenvolvimento\OODelphiBasicImplementation\BANCO.FDB?username=SYSDBA;password=masterkey;dialect=3');

  fPreparedStatement := fConnection.PrepareStatement('select * from RDB$INDICES;');

  fPreparedStatement.ExecutePrepared;

end;
Now this is the same code, with a simple modification ;

Code: Select all

procedure TForm1.btnTmpClick(Sender: TObject);
var
  fConnection        : IZConnection;
  fPreparedStatement : IZPreparedStatement;
begin

  fConnection        := DriverManager.GetConnection('zdbc:firebird-2.1://127.0.0.1/C:\Desenvolvimento\OODelphiBasicImplementation\BANCO.FDB?username=SYSDBA;password=masterkey;dialect=3');

  fPreparedStatement := fConnection.PrepareStatement('select * from RDB$INDICES;');

  fPreparedStatement.ExecuteQueryPrepared;

end;
My conclusion, every time when we use the "IZPreparedStatment", to make a simple "select" command, we need to use this statement "ExecuteQueryPrepared", and the memory leaks don't occurs.

Thank to all have help-me in this singular question.

Posted: 26.05.2011, 19:36
by trupka
Hi,

I did some tests and came to similar conclusion - leak happens deeper in code, in Firebird dbc layer. Strictly speaking, it's not a bug in Zeos - low level programming needs more attention.

Posted: 18.09.2011, 21:41
by mdaems
Now a little question, why would you do a ExecutePrepared, which only returns a boolean (success or failure of a statement), when you're passing a select query? A select query implies a resultset is needed, which is only returned by ExecuteQueryPrepared.

Which explains why ExecutePrepared might cause a memory leak: probably the result of your query is loaded somehow but not released.
Not sure where it's cleaned up in ExecuteQueryPrepared. I guess (but it's just a guess!!) it's cleaned up automatically when Delphi notices you don't assign the result to a variable, freeing the resultset again.

Mark