Sign in Join

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

Mailing lists / fpc-pascal / 2011-11

Heap, Stack, HeapTrc and threads

5 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

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

Unknown author

A recent query:
Date: Mon, 21 Nov 2011 08:27:16 +0000 From: Mark Morgan Lloyd Subject: [fpc-pascal] Debugging ancient heap allocation seems not to have received a reply. The problem of debugging memory allocation, however, is wider and not just involving ancient code!

I am using:
Compiler 2.4.2: IDE 1.0.12: Windows 7, Intel CORE i7 Application: image processing. Straightforward programming come out at 8 seconds per image: test data set is about 3000 images. Conversion of the program to use multiple threads for the time consuming raw image read and process part reduced this to 3 seconds per image, once I had purged the memory leaks. Initially, my program ran out of memory after 500 to 1000 images.

HeapTrc proved to be essentially useless. Depending apparently on random factors, HeapTrc reported usually no more than 4 blocks of unfreed memory, often was unable to reveal which routine had allocated some, most or all of the remaining blocks: on occasion the HeapTrc report sputtered to a halt with error messages. In particular, HeapTrc never reported unfreed blocks for any routine in the section of code subsequently found to be in error.

At this point, I added diagnostic logging: one file for the main program and one for each thread started:-

GetHeapStatus giving TotalAddrSpace, TotalAllocated, TotalFree. plus StackBottom, SPtr, StackTop, StackLength.

These were logged at the start, strategic places within, and at the end of the main program and each thread.

At no point did the heap status reveal the growing amount of space tied up: the only odd thing was that TotalAllocated sometimes came back negative in the threads as the program approached the point of running out of memory (at the 2GB addressing limit; the machine has 6GB).

The Stack numbers were more useful, showing intermittent increases in the addresses for the thread stacks. Oddly, the StackTop is returned as zero in the threads and StackLength always comes back as the value set in the IDE Options Memory Sizes and not as the value set in BeginThread. I think the correct value is actually used.

The problem, however, was finally solved only by going through the program line by line and:
Moving all workspace arrays to Global Common, including all the workspace for the threads (100 MB or so for each of 6).
Eliminating all dynamic arrays - this involved some preliminary runs to estimate (guess) the maximum size of arrays determined at run time. Eliminating all New/Dispose pairs and such like.

Even though many arrays are thus much larger than their typical size and all of them occupy space all the time, the space required was only around 1GB - half the 2GB the program previously ate up before running out of memory.

In the course of eliminating the workspace originally allocated as dynamic arrays, I discovered 2 unmatched SetLength procedures. As I mentioned above, these were never reported by HeapTrc.

You will gather I am not too impressed with the tools provided for tackling memory allocation problems!

Andrew Bennett

Jonas Maebe
to Unknown author

On 24 Nov 2011, at 16:28, <

Show quoted text 8 lines
wrote: At no point did the heap status reveal the growing amount of space tied up: the only odd thing was that TotalAllocated sometimes came back negative in the threads as the program approached the point of running out of memory (at the 2GB addressing limit; the machine has 6GB).

The fact that the heap status counters are unreliable since the latest rewrite of the heap manager is a known problem:
* http://bugs.freepascal.org/view.php?id=15805
* http://bugs.freepascal.org/view.php?id=14315
* http://bugs.freepascal.org/view.php?id=15763

In the course of eliminating the workspace originally allocated as dynamic arrays, I discovered 2 unmatched SetLength procedures. As I mentioned above, these were never reported by HeapTrc.

That's because they don't cause memory leaks (except in case of direct pointer manipulations, but in that case crashes are more likely than memory leaks). Memory management for dynamic arrays and ansi/wide/ unicodestrings is automatic via (hidden) reference counting.

I've never seen any reports of heaptrc failing to report memory leaks. Most likely, your problems stem from internal heap fragmentation rather than from memory leaks. Such problems can usually be solved by using the "cmem" unit, which falls back to the default C library's memory manager (FPC's heap manager is generally faster, except in cases of lots of fragmentation).

Jonas

Unknown author

On: Thu, 24 Nov 2011 17:06:18 +0100 Jonas Maebe wrote

Show quoted text 13 lines
On 24 Nov 2011, at 16:28, < > wrote: > ... > only odd thing was that TotalAllocated sometimes came back negative in > the threads as the program approached the point of running out of > memory The fact that the heap status counters are unreliable since the latest rewrite of the heap manager is a known problem: * http://bugs.freepascal.org/view.php?id=15805 * http://bugs.freepascal.org/view.php?id=14315 * http://bugs.freepascal.org/view.php?id=15763

Thank you for pointing this out.

Show quoted text 14 lines
> In the course of eliminating the workspace originally allocated as > dynamic > arrays, I discovered 2 unmatched SetLength procedures. As I mentioned > above, these were never reported by HeapTrc. That's because they don't cause memory leaks (except in case of direct pointer manipulations, but in that case crashes are more likely than memory leaks). Memory management for dynamic arrays and ansi/wide/ unicodestrings is automatic via (hidden) reference counting. I've never seen any reports of heaptrc failing to report memory leaks. Most likely, your problems stem from internal heap fragmentation rather than from memory leaks.

Ah! Light dawns.
So my problems did not arise entirely from my incompetence in handling storage allocation. Thanks for the morale boost!

Such problems can usually be solved by using the "cmem" unit, which falls back to the default C library's memory manager (FPC's heap manager is generally faster, except in cases of lots of fragmentation).

I had not realized I could do this! My thought processes ran "C -> Unix -> not me under Windows" and I am currently stuck with Windows.

Jonas

Many thanks,
Andrew Bennett

Marco van de Voort
to Jonas Maebe: On 24 Nov 2011, at 16:28, < The fact that the heap status counters are unreliable since…

In our previous episode, Jonas Maebe said:

Show quoted text 6 lines
I've never seen any reports of heaptrc failing to report memory leaks. Most likely, your problems stem from internal heap fragmentation rather than from memory leaks. Such problems can usually be solved by using the "cmem" unit, which falls back to the default C library's memory manager (FPC's heap manager is generally faster, except in cases of lots of fragmentation).

IMHO if you get into trouble with this, you are already walking on the edge of the abyss. Using cmem (or any other advanced memory manager) might give short time relieve because it probably has a different allocation pattern.

But long term it is smarter to simply tackle the causes of fragmentation.

Jonas Maebe
to Marco van de Voort
Marco van de Voort wrote 6 lines
IMHO if you get into trouble with this, you are already walking on the edge of the abyss. Using cmem (or any other advanced memory manager) might give short time relieve because it probably has a different allocation pattern.

Not necessarily. The FPC heap manager is simply very bad at preventing or getting rid of heap fragmentation as soon as you use block sizes > maximum size used by the fixed freelists.

Jonas