Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Memory leak using NewAnsiString

117 views
Skip to first unread message

Arnau Font

unread,
Nov 25, 2003, 7:32:53 AM11/25/03
to
Hi,

I've tested my application using one debugger, and the results are that
there are some memory leaks, most of them involving the use of strings, like
in this case:

var
s: String;
begin
s:=ProcThatFillsTheStr(bla,bla);
DoSomethingWithString(s);
end;

The debugger says that 's' generates a memory leak, but shouldn't it be
freed automatically by the delphi compiler?

What should I do? Pass the 's' string as a var parameter to the function?
Call finalitze or SetLength(s,0) at the end of the procedure?

Thnaks!


Arnau Font

unread,
Nov 25, 2003, 8:02:47 AM11/25/03
to
"John Herbster (TeamB)" <herb-sci1_AT_sbcglobal.net> wrote in message
news:3fc34fde$1...@newsgroups.borland.com...
>
> Arnau, Some questions:
> (1) What debugger is telling you about the memory leak?
> (2) How does ProcThatFillsTheStr fill its result?
> (3) How does DoSomethingWithString(s) use "s"?
> Regards, JohnH

Thanks for the fast answer!
1.- The debugger is AQTime 3.1
2.- ProcThatFillsTheStr fills it like this:
result:=s1+s2;
Where s1 and s2 are strings, too.
3.- DoSomethingWithString(s) only assigns s to another string, like this:
obj.str:=s;


John Herbster (TeamB)

unread,
Nov 25, 2003, 7:50:26 AM11/25/03
to

"Arnau Font" <af...@nospam-ipssoft.com> wrote

> I've tested my application using one debugger, and the results
> are that there are some memory leaks, most of them involving
> the use of strings, like in this case:
>
> var s: String;
> begin
> s:=ProcThatFillsTheStr(bla,bla);
> DoSomethingWithString(s);
> end;
>
> The debugger says that 's' generates a memory leak,
> but shouldn't it be freed automatically by the delphi compiler?

Arnau, Some questions:

Kurt Barthelmess (TeamB)

unread,
Nov 25, 2003, 8:23:22 AM11/25/03
to
"Arnau Font" <af...@nospam-ipssoft.com> wrote:

>Thanks for the fast answer!
>1.- The debugger is AQTime 3.1
>2.- ProcThatFillsTheStr fills it like this:
> result:=s1+s2;
> Where s1 and s2 are strings, too.
>3.- DoSomethingWithString(s) only assigns s to another string, like this:
> obj.str:=s;

Based on that, I'd say there's a bug in your debugger<g>. It may
think that the original value of S is not deallocated (which is true)
because the function result is plugged directly into S. But since the
original value of S is an empty string, there is no need to deallocate
it before the assignment, and Delphi generates no code to do so.

Good luck.

Kurt

Brett Watters

unread,
Nov 25, 2003, 11:55:00 AM11/25/03
to
Arnau,

One easy way to find out is to put the code in a big loop. Run it 10,000
times
and see if the apps memory usage is going up.

Under Delphi 4, we ran into issues with string returning functions and
memory
leakage. It was extremely strange. The app would just forget about the
memory
in the result. When we changed the function call to a proc( var string), the
memory
leak started appearing as soon as we used the string. We tried it under
Delphi 7
and the entire thing went away, so we didn't bother trying to figure it out.

Thanks,

Brett

"Kurt Barthelmess (TeamB)" <kbarth...@compuserve.com> wrote in message
news:3fc35720....@newsgroups.borland.com...

Gabriel Corneanu

unread,
Nov 25, 2003, 3:28:10 PM11/25/03
to
I'd rather think that obj is not properly destroyed.
Because strings are reference counted, when s is deallocated the actual
string remains assigned to obj.str. If this is not deallocated, the result
is that the string allocated in s was not freed.
If you don't have other leaks, this can happen if obj is a record with a
string field and is deallocated using a dispose with a void pointer (sorry
for C term, it means a generic pointer); this is very common if using TList.
To avoid, pass to dispose a pointer to the actual record type or call
finalize.
I also use AQTime with very good results.

Regards,
Gabriel

"Kurt Barthelmess (TeamB)" <kbarth...@compuserve.com> wrote in message
news:3fc35720....@newsgroups.borland.com...

Kurt Barthelmess (TeamB)

unread,
Nov 25, 2003, 5:57:32 PM11/25/03
to
"Gabriel Corneanu" <nospam.gabr...@yahoo.com> wrote:

>I'd rather think that obj is not properly destroyed.
>Because strings are reference counted, when s is deallocated the actual
>string remains assigned to obj.str. If this is not deallocated, the result
>is that the string allocated in s was not freed.

imho, that is a bug in the debugger. If it tells you that something (S
in this case) was not deallocated when it clearly is, then it is not
only unhelpful, but misleading in its warnings. Had it said that
"obj.str" was not deallocated, you'd have something useful to go on.

Kurt

Gabriel Corneanu

unread,
Nov 26, 2003, 6:50:36 AM11/26/03
to
This is not quite right. It doesn't say "who" (as a variable) is not
deallocated; it sais that "something" (memory area) is not deallocated and
it shows you where it was allocated (s in this case). There is no way to
tell you where it should be deallocated. S was deallocated, but the memory
reference counter was only decremented because it is still used somewhere
else.
If you don't believe me, try it yourself. I recently found a lot of this
kind of leaks.
Example:
type TRec = record
str : string;
end;
PRec = ^TRec;

var
s : string;
P : Pointer;
PP: PRec;
begin
s := 'hello';
new(PP);
PP.str := s;
P := PP;
//only one of these
dispose(P);//this will produce the leak
dispose(PP);//this is ok
end;

Gabriel

"Kurt Barthelmess (TeamB)" <kbarth...@compuserve.com> wrote in message

news:3fc3ddb0...@newsgroups.borland.com...

Kurt Barthelmess (TeamB)

unread,
Nov 26, 2003, 10:53:36 AM11/26/03
to
"Gabriel Corneanu" <nospam.gabr...@yahoo.com> wrote:

>This is not quite right. It doesn't say "who" (as a variable) is not
>deallocated; it sais that "something" (memory area) is not deallocated and
>it shows you where it was allocated (s in this case). There is no way to
>tell you where it should be deallocated. S was deallocated, but the memory
>reference counter was only decremented because it is still used somewhere
>else.

I understand what it is doing. But it would not be helpful to me to
get such an advisory that is so misleading.

>I recently found a lot of this
>kind of leaks.

[clip]


> dispose(P);//this will produce the leak

I don't know how to answer that except to ask "What did you expect?"

Kurt

Rudy Velthuis (TeamB)

unread,
Nov 26, 2003, 10:13:02 AM11/26/03
to
Kurt Barthelmess (TeamB) wrote:

> "Arnau Font" <af...@nospam-ipssoft.com> wrote:
>
> > Thanks for the fast answer!
> > 1.- The debugger is AQTime 3.1
> > 2.- ProcThatFillsTheStr fills it like this:
> > result:=s1+s2;
> > Where s1 and s2 are strings, too.
> > 3.- DoSomethingWithString(s) only assigns s to another string, like
> > this: obj.str:=s;
>
> Based on that, I'd say there's a bug in your debugger<g>.

Perhaps S is a global variable? In that case it may never be explicitly
cleared, although Windows will take care of that after the program has
ended.

--
Rudy Velthuis (TeamB)

"The only thing necessary for the triumph of evil is for good men to do
nothing."
-- Edmund Burke (1729-1797)

Gabriel Corneanu

unread,
Nov 26, 2003, 11:33:27 AM11/26/03
to

"Kurt Barthelmess (TeamB)" <kbarth...@compuserve.com> wrote in message
news:3fc4c9c0...@newsgroups.borland.com...

> I understand what it is doing. But it would not be helpful to me to
> get such an advisory that is so misleading.

Yes, I agree it is a little misleading, but that's when you don't consider
reference counting; once you understand it's easier to look at the right
direction. I keep repeating: do you see a way to tell where should be the
string destroyed?
This problem is the same when working with classic memory allocations; you
reserve a space, store the pointer than later deallocate when you don't need
it anymore. The profiler can help and show you where you allocated the
space; it's your problem to know where to deallocate it.

> >I recently found a lot of this
> >kind of leaks.
> [clip]
> > dispose(P);//this will produce the leak
>
> I don't know how to answer that except to ask "What did you expect?"

This simple example is what I think it happens in his situation. As I said,
I believe he should see where the string is going; it is very likely to
happen this way exactly because in general the strings are properly
deallocated.
On the other hand maybe the example was not clear enough; you can have a
large number of fields in the record (any kind except strings and
interfaces) and they will be properly destroyed with dispose(P), only the
string not. If you look at the CPU listing you see that exactly the finalize
call is missing.
What I wanted to point is that probably he is deallocating the pointer but
via a generic pointer and that could be the cause. I believe this because
otherwise he would get other leak reports about the record.

Gabriel


Kurt Barthelmess (TeamB)

unread,
Nov 26, 2003, 3:27:01 PM11/26/03
to
"Rudy Velthuis (TeamB)" <rvel...@gmx.de> wrote:

>Perhaps S is a global variable? In that case it may never be explicitly
>cleared, although Windows will take care of that after the program has
>ended.

Except that Arnau wrote:

>Call finalitze or SetLength(s,0) at the end of the procedure?

Kurt

Kurt Barthelmess (TeamB)

unread,
Nov 26, 2003, 3:24:47 PM11/26/03
to
"Gabriel Corneanu" <nospam.gabr...@yahoo.com> wrote:

>Yes, I agree it is a little misleading, but that's when you don't consider
>reference counting; once you understand it's easier to look at the right
>direction. I keep repeating: do you see a way to tell where should be the
>string destroyed?

That isn't possible to do, of course. And I don't have a problem with
the debugger telling me that such and such a memory block has a
non-zero reference count. It might even tell me, "Here is a list of
the places the count was bumped, and here's a list of the places it
was decremented." But telling me the problem is "here" when it is
actually "there" is a problem. A magician does this professionally,
but the debugger is not on stage<g>.

>On the other hand maybe the example was not clear enough; you can have a
>large number of fields in the record (any kind except strings and
>interfaces) and they will be properly destroyed with dispose(P), only the
>string not. If you look at the CPU listing you see that exactly the finalize
>call is missing.

Yes. Which is why I wrote "What did you expect?" Using an untyped
pointer is a terrible practice, imho. One of the strong points of OP
over C (as far as Delphi users are concerned, of course, C programmers
would not agree<g>) is its strong typing. To deliberately obfuscate
code like that can't be considered good practice.

Kurt

Arnau Font

unread,
Nov 27, 2003, 5:12:05 AM11/27/03
to

"Gabriel Corneanu" <nospam.gabr...@yahoo.com> wrote in message
news:3fc49385$1...@newsgroups.borland.com...

> If you don't believe me, try it yourself. I recently found a lot of this
> kind of leaks.
> Example:
> type TRec = record
> str : string;
> end;
> PRec = ^TRec;
>
> var
> s : string;
> P : Pointer;
> PP: PRec;
> begin
> s := 'hello';
> new(PP);
> PP.str := s;
> P := PP;
> //only one of these
> dispose(P);//this will produce the leak
> dispose(PP);//this is ok
> end;
>
Hi, thanks for your time!

That might be one case, and I'm looking at it, but I have other memory leaks
like this one:

procedure TFInicial.TimerMemoriaTimer(Sender: TObject);
var
Memo:THeapStatus;
begin
TimerMemoria.Enabled:=false;
Memo:=GetHeapStatus;
laMem.Caption:=IntToStr(Memo.TotalAllocated); //Here sometimes there is a
memory leak
EstadistiquesManager.Obertures(num, perce); //Global variable
//In the format function sometimes causes another memory leak
laObertures.Caption:=Format('%d (%2f%%)',[num, perce]);
TimerMemoria.Enabled:=true;
end;

Any ideas? I just can't get the point.As you see, there are no pointers
involved.
The problem is that my application should be active 'for ages' so memory
leaks are quite a problem.

Thanks!

Arnau.


Kurt Barthelmess (TeamB)

unread,
Nov 27, 2003, 5:59:37 AM11/27/03
to
"Arnau Font" <af...@nospam-ipssoft.com> wrote:

>I have other memory leaks
>like this one:
>
>procedure TFInicial.TimerMemoriaTimer(Sender: TObject);
>var
> Memo:THeapStatus;
>begin
> TimerMemoria.Enabled:=false;
> Memo:=GetHeapStatus;
> laMem.Caption:=IntToStr(Memo.TotalAllocated); //Here sometimes there is a
>memory leak

What is "laMem"? If it is a TLabel or similar standard component,
there is no memory leak there.

> EstadistiquesManager.Obertures(num, perce); //Global variable
> //In the format function sometimes causes another memory leak
> laObertures.Caption:=Format('%d (%2f%%)',[num, perce]);

I can't tell what is going on here with the external call, but the
Format function is one that, like assigning a Caption to a TLabel,
does not leak memory.

>Any ideas? I just can't get the point.As you see, there are no pointers
>involved.

No untyped pointers at least. Technically the strings and the
parameters to Format are. But those are being cleaned up.

>The problem is that my application should be active 'for ages' so memory
>leaks are quite a problem.

Your application may have memory leaks, but I don't think this is
where they are occuring. Have you tried any of the other memory
debuggers? I sincerely think AQTime may be missing some deallocations
and giving you misleading warnings.

Good luck.

Kurt

Arnau Font

unread,
Nov 27, 2003, 6:09:07 AM11/27/03
to
"Kurt Barthelmess (TeamB)" <kbarth...@compuserve.com> wrote in message
news:3fc5d77e....@newsgroups.borland.com...

> "Arnau Font" <af...@nospam-ipssoft.com> wrote:
>
>
> What is "laMem"? If it is a TLabel or similar standard component,
> there is no memory leak there.

Yes, it is a TLabel, sorry, that's why I find it so strange.


>
> Your application may have memory leaks, but I don't think this is
> where they are occuring. Have you tried any of the other memory
> debuggers? I sincerely think AQTime may be missing some deallocations
> and giving you misleading warnings.


Yeah, probably you are right, because this is wierd.
Could you recommend me any other memory debugger? I'll give them a try.

Thanks!


Arnau Font

unread,
Nov 27, 2003, 7:08:11 AM11/27/03
to
So sorry!!! After looking a lot of places, I've seen that AQTime needs the
project to be compiled with the 'build with run-time packages' option
activated!!!

Only one memory leak remaining ;)

Thanks!

Sorry about all the mess! Thanks a lot for your comments!
"Arnau Font" <af...@nospam-ipssoft.com> wrote in message
news:3fc34bf4$1...@newsgroups.borland.com...

Rudy Velthuis (TeamB)

unread,
Nov 27, 2003, 5:39:56 AM11/27/03
to
Kurt Barthelmess (TeamB) wrote:

> "Rudy Velthuis (TeamB)" <rvel...@gmx.de> wrote:
>
> > Perhaps S is a global variable?

> Except that Arnau wrote:


>
> > Call finalitze or SetLength(s,0) at the end of the procedure?

Oh, I missed that.


--
Rudy Velthuis (TeamB)

"In theory, there is no difference between theory and practice. But, in
practice, there is."
- Jan L.A. van de Snepscheut

Kurt Barthelmess (TeamB)

unread,
Nov 27, 2003, 7:07:10 AM11/27/03
to
"Arnau Font" <af...@nospam-ipssoft.com> wrote:

>Could you recommend me any other memory debugger? I'll give them a try.

Sorry, but I don't recommend stuff I haven't used. And I've been very
lucky in that I've never run into this sort of memory leak before so I
have not needed such a debugger. Someone else may have some
suggestions.

Good luck.

Kurt

0 new messages