Memory leaks - UnicodeString

delphi package - automated exception handling
Post Reply
Han312
Posts: 54
Joined: Mon Mar 14, 2016 3:49 pm

Memory leaks - UnicodeString

Post by Han312 »

I get memory leaks reported when I try to fill a grid and do not really understand what is the reason for it or what I can do against it.
I simplify the situation:

Code: Select all

type
  eColType  = ( eUnused, eText, eInteger, eCheckBox, eColorDlg  );

  tCellInfo = record
    Text : string;
    case CellType:eColType of
      eInteger    : ( Count   : integer );
      eCheckBox   : ( Checked : boolean );
      eColorDlg   : ( Color   : tColor  );
  end; {tCellInfo}

function Fill( var pCellInfo : tCellInfo ) : boolean;
begin
...
  pCellInfo.Text := 'Text'; //<-- this is reported by madexcept
...
end;
madExceptDbg 1575 GetMemCallback
System 51 @GetMem
System 51 @NewUnicodeString
System 51 @UStrFromPWCharLen
System 51 @UStrCopy
System.Classes TStrings.GetValue
It seems so whether the string in the record is the problem. After changing it to a shortstring madExcept doesn't report the leak anymore. But i need a string.
What can I do to keep the string and have no memory leak?!
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: Memory leaks - UnicodeString

Post by madshi »

The problem is not the allocation. How are you freeing the record?
Han312
Posts: 54
Joined: Mon Mar 14, 2016 3:49 pm

Re: Memory leaks - UnicodeString

Post by Han312 »

There is a loop to fill every cell of the grid und the record is resetted :

FillChar( pCellInfo , sizeof( pCellInfo ) , #0 );

Not sure whether this is still correct with strings. After seeing this I believe that the string was earlier a pChar and I changed it to string a while ago.

I also don't free the record. This is necessary with strings?!

pCellInfo.Text := ''
seems to solve my problem.
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: Memory leaks - UnicodeString

Post by madshi »

Well, I've only seen the type declaration and a function which accepts a pointer to the record. So I assumed you were allocating instances of that record? If that's not the case, then you don't have to free the records, of course.

All dynamic stuff in Delphi (dynamic ansi + unicode strings, interfaces, dynamic arrays etc) are normally automatically freed by Delphi, in the moment when it makes sense. However, if you overwrite such dynamic elements "behind Delphi's back" by using FillChar or ZeroMemory or something similar, in the moment when Delphi wants to cleanup the dynamic parts of the record, it's already zero, so Delphi assumes that the dynamic string was already released. So using FillChar to clear a record which has a dynamic element in it will produce a memory leak.

The cleanest solution is to use "Finalize(record)" before zeroing the memory of the record. Of course you can also manually set all dynamic elements to "nil" or an empty string. But "Finalize()" is easier because it will do everything automatically for you. So if you later add another dynamic element to the record, you don't have to add more code to properly free it, "Finalize" will do that for you. Please note that "Finalize()" expects the record, not a pointer to the record.
Han312
Posts: 54
Joined: Mon Mar 14, 2016 3:49 pm

Re: Memory leaks - UnicodeString

Post by Han312 »

Thanks for your reply and the explanation. To be honestly - I would have never guessed that FillChar could be the reason for that leak. I was only wondering why that leak appeared not all the time but only in some cases. Now it is so simple to see in which cases.

So it would be the best (also for future changes in the program code) to call Finalize always before FillChar - uninteresting whether the record includes dynamic data or not?
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: Memory leaks - UnicodeString

Post by madshi »

That's correct, calling Finalize should never harm - unless you allocate a record with a memory allocation function which doesn't initialize the memory to zero! If a record has random data in it, calling Finalize will try to release the random dynamic pointers, which will result in a crash.
Han312
Posts: 54
Joined: Mon Mar 14, 2016 3:49 pm

Re: Memory leaks - UnicodeString

Post by Han312 »

I read http://stackoverflow.com/questions/1106 ... hi-at-once.

Would be there a difference between

Finalize( pCellInfo);
FillChar( pCellInfo , sizeof( pCellInfo ) , #0 );

and

pCellInfo := Default( tCellInfo);
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: Memory leaks - UnicodeString

Post by madshi »

I don't know "Default".

As I wrote before, Finalize wants the record itself, *NOT* the pointer to it!!!!!!!! So your code "Finalize(pCellInfo)" is definitely wrong. It needs to be "Finalize(pCellInfo^)". BTW, your FillChar call is wrong, too. It zeroes the record, but only in the size of "sizeof(pCellInfo)". Since "pCellInfo" is a pointer, sizeof(pCellInfo) is always 4 in 32bit and 8 in 64bit. What you really want is "sizeof(pCellInfo^)".

No offense, but I think you may want to refresh your knowledge about pointers... :wink: :confused:
Han312
Posts: 54
Joined: Mon Mar 14, 2016 3:49 pm

Re: Memory leaks - UnicodeString

Post by Han312 »

I don't quiet understand.
I think that there is a misunderstanding since I didn't mention where I call FillChar and also that the p in pCellInfo confused you and you thought that it is a pointer. This is my fault and I could have been more clear.
But in my opinion I don't use anywhere the pointer of the record.

Code: Select all

type
  tCellInfo = record
    ...
  end;

procedure Test
var CellInfo : tCellinfo;
begin
  repeat
    ...
    Finalize( CellInfo );
    FillChar( CellInfo , sizeof( CellInfo ) , #0 );
    Fill( CellInfo );
    ...
  until ...
end;
Isn't that correct?! Or am I totally wrong?

sizeof( CellInfo ) is always 16. Also within of the Fill procedure
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: Memory leaks - UnicodeString

Post by madshi »

Oh, my fault, sorry. That was indeed a misunderstanding on my part, due to the "p" I thought it was a pointer.

So everything is alright with your code.
Post Reply