Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2014-11

Problem with heaptrc

7 messages · 3 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Xiangrong Fang

Hi All,

I use heap trace utility to see if there are memory leak in my program. The source is here:

https://github.com/xrfang/fpcollection/blob/aefa04f0374c94298facd8d57d4a25dafe10b753/src/demos/cache/demo.lpr

My problem is, at the beginning of the main program, I have a costant definition:

const

  ITEM_COUNT = 5000000;

If I set ITEM_COUNT to a small value, say 50 or 5000, everything is OK, no memory leak. But with the above value, it will cause HEAPTRC to fall in an endless loop, generating messages like:

Call trace for block $00007F41693AA680 size 40
$000000000040071F line 29 of demo.lpr
$0000000000400180

While line 29 is this:

27  for i := 0 to ITEM_COUNT - 1 do begin
28    for j := 0 to 4 do key[j] := $deadbeef + i + j;
29    h.Add(@key, SizeOf(PtrUInt) * 5, Pointer($deadbeef + i));
30  end;
Could anyone tell me why heaptrc will fall in an endless loop, and does my
program have memory leak?

Thanks!

Xiangrong

Reply by email

Tomas Hajny
to Xiangrong Fang

On 9 Nov 14, at 21:58, Xiangrong Fang wrote:

Hi Xiangrong,

Show quoted text 26 lines
I use heap trace utility to see if there are memory leak in my program. The source is here: https://github.com/xrfang/fpcollection/blob/aefa04f0374c94298facd8d57d4a25dafe10b753/src/demos/cache/demo.lpr My problem is, at the beginning of the main program, I have a costant definition: const ITEM_COUNT = 5000000; If I set ITEM_COUNT to a small value, say 50 or 5000, everything is OK, no memory leak. But with the above value, it will cause HEAPTRC to fall in an endless loop, generating messages like: Call trace for block $00007F41693AA680 size 40 $000000000040071F line 29 of demo.lpr $0000000000400180 While line 29 is this: 27 for i := 0 to ITEM_COUNT - 1 do begin 28 for j := 0 to 4 do key[j] := $deadbeef + i + j; 29 h.Add(@key, SizeOf(PtrUInt) * 5, Pointer($deadbeef + i)); 30 end; Could anyone tell me why heaptrc will fall in an endless loop, and does my program have memory leak?

Are you sure that it really is endless (i.e. did you let to run for a sufficiently long time)? If you increase the amount of allocated blocks (which is what happens in case of increasing your constant), traversing through all the blocks (especially if they are not freed at the end) may indeed take fairly long time...

Tomas

Reply by email

Michael Van Canneyt
to Tomas Hajny
Tomas Hajny wrote 37 lines
On 9 Nov 14, at 21:58, Xiangrong Fang wrote: Hi Xiangrong, > I use heap trace utility to see if there are memory leak in my program. > The source is here: > > https://github.com/xrfang/fpcollection/blob/aefa04f0374c94298facd8d57d4a25dafe10b753/src/demos/cache/demo.lpr > > My problem is, at the beginning of the main program, I have a costant > definition: > > const > ITEM_COUNT = 5000000; > If I set ITEM_COUNT to a small value, say 50 or 5000, everything is OK, no > memory leak. But with the above value, it will cause HEAPTRC to fall in an > endless loop, generating messages like: > > Call trace for block $00007F41693AA680 size 40 > $000000000040071F line 29 of demo.lpr > $0000000000400180 > > While line 29 is this: > > 27 for i := 0 to ITEM_COUNT - 1 do begin > 28 for j := 0 to 4 do key[j] := $deadbeef + i + j; > 29 h.Add(@key, SizeOf(PtrUInt) * 5, Pointer($deadbeef + i)); > 30 end; > Could anyone tell me why heaptrc will fall in an endless loop, and does my > program have memory leak? Are you sure that it really is endless (i.e. did you let to run for a sufficiently long time)? If you increase the amount of allocated blocks (which is what happens in case of increasing your constant), traversing through all the blocks (especially if they are not freed at the end) may indeed take fairly long time...

It is not endless. I tested, it simply takes several minutes to produce a stack trace for 2910911 (yes, 3 million) unfreed blocks of memory. The resulting heap.trc file is 300Mb.

Michael.

Reply by email

Xiangrong Fang
to Tomas Hajny: Are you sure that it really is endless (i.e. did you let to run for a sufficiently long…

2014-11-09 22:05 GMT+08:00 Tomas Hajny :

Show quoted text 8 lines
On 9 Nov 14, at 21:58, Xiangrong Fang wrote: Are you sure that it really is endless (i.e. did you let to run for a sufficiently long time)? If you increase the amount of allocated blocks (which is what happens in case of increasing your constant), traversing through all the blocks (especially if they are not freed at the end) may indeed take fairly long time...

​You are right Tomas, it finished, generated a 300M+(!) trace file, looks like this:

Reply by email

Xiangrong Fang
to Xiangrong Fang

2014-11-09 22:14 GMT+08:00 Xiangrong Fang :

Show quoted text 15 lines
2014-11-09 22:05 GMT+08:00 Tomas Hajny : > On 9 Nov 14, at 21:58, Xiangrong Fang wrote: > > Are you sure that it really is endless (i.e. did you let to run for a > sufficiently long time)? If you increase the amount of allocated > blocks (which is what happens in case of increasing your constant), > traversing through all the blocks (especially if they are not freed > at the end) may indeed take fairly long time... > ​You are right Tomas, it finished, generated a 300M+(!) trace file, looks like this: ​Heap dump by heaptrc unit

8137678 memory blocks allocated : 258591549/258591552 5226767 memory blocks freed : 142155109/142155112 2910911 unfreed memory blocks : 116436440
True heap size : 951812096
True free heap : 392917184
Should be : 462779048
Call trace for block $00007F57C456D680 size 40
$000000000040071F line 29 of demo.lpr
$0000000000400180

The last 3 likes repeated until the end of 300M log data!

Why when ITEM_COUNT is small, there is no memory leak, but when it is large, there are so many leaks?

Xiangrong​

Reply by email

Michael Van Canneyt
to Xiangrong Fang
Xiangrong Fang wrote 27 lines
2014-11-09 22:14 GMT+08:00 Xiangrong Fang : 2014-11-09 22:05 GMT+08:00 Tomas Hajny : On 9 Nov 14, at 21:58, Xiangrong Fang wrote: Are you sure that it really is endless (i.e. did you let to run for a sufficiently long time)? If you increase the amount of allocated blocks (which is what happens in case of increasing your constant), traversing through all the blocks (especially if they are not freed at the end) may indeed take fairly long time... ​You are right Tomas, it finished, generated a 300M+(!) trace file, looks like this: ​Heap dump by heaptrc unit 8137678 memory blocks allocated : 258591549/258591552 5226767 memory blocks freed     : 142155109/142155112 2910911 unfreed memory blocks : 116436440 True heap size : 951812096 True free heap : 392917184 Should be : 462779048 Call trace for block $00007F57C456D680 size 40   $000000000040071F line 29 of demo.lpr   $0000000000400180 The last 3 likes repeated until the end of 300M log data! Why when ITEM_COUNT is small, there is no memory leak, but when it is large, there are so many leaks?

I didn't check in detail, but looking at the code, it seems likely that you overwrite memory somewhere in your tcache class. As soon as that happens somewhere, memory is corrupted and is unlikely to be free corrected.
The greater the number of items, the greater the probability of memory corruption.

Code like this:

    ci := PCacheItem((buf + SizeOf(Pointer) * Random(FDepth))^);
     for i := 0 to FDepth - 1 do begin
       slot := buf + SizeOf(Pointer) * i;
       if Pointer(slot^) = nil then begin
         Inc(N);
         Pointer(slot^) := GetMem(SizeOf(TCacheItem));
         ci := PCacheItem(slot^);

makes me frown, because the first assignment to ci is useless, so highly suspect.

Michael.

Reply by email

Xiangrong Fang
to Michael Van Canneyt

2014-11-09 22:38 GMT+08:00 Michael Van Canneyt :

Show quoted text 12 lines
Code like this: ci := PCacheItem((buf + SizeOf(Pointer) * Random(FDepth))^); for i := 0 to FDepth - 1 do begin slot := buf + SizeOf(Pointer) * i; if Pointer(slot^) = nil then begin Inc(N); Pointer(slot^) := GetMem(SizeOf(TCacheItem)); ci := PCacheItem(slot^); makes me frown, because the first assignment to ci is useless, so highly suspect.

​You are right Michael. I just found that if there is no free slot, I use "Random Replacement" to dump one of the existing cached item, whose key is not freed, which caused memory leak.

Thanks!

Xiangrong.​

Reply by email