[fpc-devel]Problems with AnsiStrings (memory leak)
Florian Klaempfl
florian at klaempfl.de
Sun Nov 19 17:12:47 CET 2000
At 15:50 19.11.00 +0100, you wrote:
>Hello,
>
>I encountered a problem using AnsiStrings. It isn't a real bug, but
>can make problems, like it does for me.
>
>I noticed it with Free Pascal version 1.1, snapshot 17/11/2000 under
>Linux (i386).
>
>The problem is that when altering AnsiStrings the greatest available
>memory block is becoming smaller and smaller, but much smaller than it
>is really needed.
>
>For example, I made the following example program that creates a
>string of 5000 chars by adding one char at a time. I gave the program
>1 mb of heap memory but it runs out of memory.
>
>Here is this program:
>
>-----------------8<------------------8<-------------------------------
>
>{$MODE Delphi} // I prefer Delphi programming style
>{$M 16387, 1000000} // 16 kb stack, 1 mb heap
>
>
>program StringTest;
>
>var
> S : AnsiString; // test-string
> i : Integer; // count-variables
> StartMem : Integer; // total free memory at startup
> StartMax : Integer; // greatest free memory block atstartup
> c : Char;
>
>begin
> { This disables the automatic heap growing when more memory is needed.
> As with the $M switch defined, the program has 1 mb of heap available,
> that should be enough for a 5,000 chars string... }
> HeapError := NIL;
>
>
> writeln('ANSISTRINGS TEST');
> writeln;
> writeln('Please note heap griwing is disabled. ',
> 'The program may only use 1 mb of heap.');
>
> StartMem := MemAvail;
> StartMax := MaxAvail;
> writeln('Memory at program start: ', StartMem, ' bytes free, ',
> StartMax, ' in largest block.');
>
> writeln('Hit RETURN to continue...');
> ReadLn;
>
> c:='.';
>
> S:='start';
> For i:=1 to 5000 do
> begin
> S := S + c; // simple instruction to add one single character to a string
>
> writeln('String length = ', Length(S),' chars; memory: ',
> MemAvail,' free, ',MaxAvail,' largest block.');
> end;
>
> writeln('memory loss: ',StartMem-MemAvail, ' bytes, ',
> StartMax-MaxAvail, ' in largest block');
>
> writeln('done.');
> writeln('S="',S,'"');
> writeln('That is, ', Length(S),' chars.');
> writeln('Memory at program end: ', MemAvail, ' bytes free, ',
> MaxAvail, ' in largest block.');
>
>end.
>
>-----------------8<------------------8<-------------------------------
>
>
>And on my machine it generates the following output:
>
>ANSISTRINGS TEST
>
>Please note heap griwing is disabled. The program may only use 1 mb of heap.
>Memory at program start: 999920 bytes free, 999920 in largest block.
>Hit RETURN to continue...
>String length = 6 chars; memory: 999856 free, 999856 largest block.
>String length = 7 chars; memory: 999856 free, 999824 largest block.
>String length = 8 chars; memory: 999856 free, 999824 largest block.
>String length = 9 chars; memory: 999856 free, 999824 largest block.
>String length = 10 chars; memory: 999856 free, 999824 largest block.
>[...]
>String length = 3958 chars; memory: 995904 free, 7904 largest block.
>String length = 3959 chars; memory: 995904 free, 3984 largest block.
>String length = 3960 chars; memory: 995904 free, 7904 largest block.
>String length = 3961 chars; memory: 995904 free, 3984 largest block.
>String length = 3962 chars; memory: 995904 free, 7904 largest block.
>String length = 3963 chars; memory: 995904 free, 3984 largest block.
>String length = 3964 chars; memory: 995904 free, 7904 largest block.
>String length = 3965 chars; memory: 995904 free, 3984 largest block.
>String length = 3966 chars; memory: 995904 free, 7904 largest block.
>String length = 3967 chars; memory: 995904 free, 3984 largest block.
>Runtime error 203 at 0x080503B0
> 0x080503B0
> 0x0804FF40
> 0x0804C1F6
> 0x0804C696
> 0x0804C379
> 0x080539BF
> 0x080480B0
> 0x00000000
>
>
>As you can see, the used memory begins to grow exponencially (well, to
>be exact, the free memory sinks correctly).
>
>Can you correct this behavior? I have a big problem with a web server
>application that has to process large strings and in some cases it
>runs out of memory, even with 15 mb heap.
This is nearly impossible to fix because the problem is the memory
fragmentation:
there are a lot of memory blocks allocated and deallocated but the
new blocks never fit into the available free blocks because there
is new data concatenated.
I suggest that you estimate first, how long you string will get and then
you do a setlength(s,<estimated length>);
If you can't estimate the length, but you know that you strings are quite
large,
say several kB, you do a manual setlength in some kB steps (untested):
aktsize:=1024;
setlength(s,1024);
For i:=1 to 5000 do
begin
S := S + c; // simple instruction to add one single character to a string
if length(s)=aktsize then
begin
inc(aktsize,1024);
setlength(s,aktsize);
end;
writeln('String length = ', Length(S),' chars; memory: ',
MemAvail,' free, ',MaxAvail,' largest block.');
end;
This will also improve the performance of your program a lot because much
fewer memory (re)allocations are performed and because setlength can use
reallocmem
while s:=s+c always performs a copy with move.
More information about the fpc-devel
mailing list