Link to home
Start Free TrialLog in
Avatar of reynaerde
reynaerde

asked on

Memory leak - how to get rid of custom created object

Well, this has already cost me too many hours so I decided to sign up with experts-exchange, I hope you can help me here.

I'm not really a programming crack, so I just might be doing something really stupid but here is what I tried to do:

The object is part of a larger program, it is defined in one unit(say unit A) as follows:

TLattice = class(TObject)
  cell : array of array of TCell;
  size_dim1, size_dim2, lifetime : Integer;
  cellCountH, cellCountA1, cellCountA2, cellCountA3, cellCountD : array of integer;
  active_drugs : integer;
  drugs_in_system : array of TDrug;
  constructor create(Dimensie1, Dimensie2 : Integer);
end;

TCell and TDrug are defined as follows:

TCell = class(TObject)
  status : cell_status;
  nA1, nA2 : integer;
  strand: integer;
  to_update : cell_status;
  lifetime: integer;
  resist: integer;
  activated: bool;
  constructor create();
end;

TDrug = class(TObject)
  name: string;
  N: integer;
  Presp : double;
  lifetime: integer;
  constructor create();
end;

And, to be as complete as possible, the constructor for TLattice is this:

constructor TLattice.create(Dimensie1, Dimensie2 : Integer);
var
  Temp_Cell : TCell;
  Teller1, Teller2 : Integer;
begin

    setlength(cell,Dimensie1+(2*bufferzone),Dimensie2+(2*bufferzone));  // set dynamic array => dimensions + bufferzone
    self.size_dim1 := Dimensie1;
    self.size_dim2 := Dimensie2;

    setlength(cellCountH,1000);
    setlength(cellCountA1,1000);
    setlength(cellCountA2,1000);
    setlength(cellCountA3,1000);
    setlength(cellCountD,1000);

    for Teller1 := 0 to Dimensie1 + (2*bufferzone -1) do
    begin
      for Teller2 := 0 to Dimensie2 + (2*bufferzone -1) do  // vul lattice 2e dimensie
      begin
        Temp_Cell := TCell.create();
        self.cell[Teller1,Teller2] := Temp_Cell;
      end;
    end;
end;

Now, in one unit(unit A) I have registered a variable called Lattice as a global variable(in that unit)

var
   Lattice : TLattice;


From another unit(unit B) I call a wrapper procedure which is as follows:

procedure wrapper(some variables..)
begin
   Lattice := TLattice.create(700,700);

   Do some things with the Lattice..
   
   Then, in the end, I try to get rid of this object since I call this wrapper procedure many times and it causes gigantic memory leaks
   First I simply tried Lattice.free(); but this doesn't seem to work(I get a memory access error)
   (I don't access the Lattice anymore after this call)
   Next I tried to make a custom procedure(freeLattice) to clean it up and though it partly works(much less memory leak) it still doesn't totally solve  
   my problem
end;

procedure freeLattice(Lattice : TLattice);
var
  Teller, Teller1, Teller2, Dimensie1, Dimensie2: Integer;
begin

  Dimensie1 := Lattice.size_dim1;
  Dimensie2 := Lattice.size_dim2;

  for Teller1 := bufferzone to Dimensie1 + (bufferzone -1) do
  begin     for Teller2 := bufferzone to Dimensie2 + (bufferzone -1) do  
    begin
      Lattice.cell[Teller1,Teller2].Free();
    end;
  end;

  setlength(Lattice.cell,0,0);

  setlength(Lattice.cellCountH,0);
  setlength(Lattice.cellCountA1,0);
  setlength(Lattice.cellCountA2,0);
  setlength(Lattice.cellCountA3,0);
  setlength(Lattice.cellCountD,0);

  setlength(Lattice.drugs_in_system,0);
 
end;

I hope someone can shed some light on this! :)
Avatar of LRHGuy
LRHGuy

Dynamic arrays are freed when their refernece count goes to zero, so you shouldn't have to any zeroing of them.

You probably need to release the drugs array, too...

TLattice=class
  destructor Destroy;
    override;
end;

Destructor TLattice.Destroy;

create(Dimensie1, Dimensie2 : Integer);
var
  Teller1, Teller2 : Integer;
begin

    for Teller1 := 0 to Size_Dim1 + (2*bufferzone -1) do
    begin
      for Teller2 := 0 to Size_Dim2 + (2*bufferzone -1) do
      begin
        self.cell[Teller1,Teller2].free;
      end;
    end;

  //Free Drugs_In_System array here...
  for x:=? to ? do
   Drugs_in_System[x].free;



  inherited destroy;
end;
ASKER CERTIFIED SOLUTION
Avatar of LRHGuy
LRHGuy

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of reynaerde

ASKER

Well, unfortunately this doesn't change anything (other than perhaps a few bits less, the Drugs_in_system array is not used in my program yet)
Also, I find it strange that I get an error when I insert Lattice.free();
The exact error reads:

project raised exception class EAccessViolation with message 'Access violation at address blabla in module project_name. Read of address blabla
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
From the DELPHI 7 help:

To declare multidimensional dynamic arrays, use iterated array of ... constructions. For example,

type TMessageGrid = array of array of string;
var Msgs: TMessageGrid;

declares a two-dimensional array of strings. To instantiate this array, call SetLength with two integer arguments. For example, if I and J are integer-valued variables,

SetLength(Msgs,I,J);

allocates an I-by-J array, and Msgs[0,0] denotes an element of that array.
Actually, I just got it from the Delphi help(using Delphi 7)

'To declare multidimensional dynamic arrays, use iterated array of ... constructions. For example,

type TMessageGrid = array of array of string;
var Msgs: TMessageGrid;

declares a two-dimensional array of strings. To instantiate this array, call SetLength with two integer arguments. For example, if I and J are integer-valued variables,

SetLength(Msgs,I,J);

allocates an I-by-J array, and Msgs[0,0] denotes an element of that array.'

I know the 2-dimensional array consists of arrays within arrays, but that suits my purpose fine.

Thanks for the comments about the low(), high() and length() methods though.
It might be a problem with the USAGE of lattice. I tried all the code that's been posted and don't get any errors. Not even a memory leak. I do not have the create/destroy methods for tcell though.

It's possible something your doing with lattice is overwriting memory or some other problem.
Just to clarify...I'm using your lattice.create, my lattice.destroy and doing this:

procedure TForm2.Button2Click(Sender: TObject);
begin
   Lattice := TLattice.create(700,700);
   lattice.free;
end;

With no error.

If you post more code (tcell.create) and some usage, someone may be able to shed some light on it.
Ah, yes! You are entirely right. As unfortunately happens so often I overlooked something quite important.
I was under the impression I was clearing the Lattice using

for Teller1 := bufferzone to Dimensie1 + (bufferzone -1) do
  begin
    for Teller2 := bufferzone to Dimensie2 + (bufferzone -1) do  
    begin
      Lattice.cell[Teller1,Teller2].Free();
    end;
  end;

But clearly I needed to get the whole array (0 to Size_Dim2 + (2*bufferzone -1))

Thanks a bunch for helping!
(and thanks to alex for giving me some pointers for using high, low etc)