Free Pascal memory leak caused by methods with a pointer parameter

After replacing the AnsiString type types with TBytes (a string array) using the ToBytes method (see below), Delphi reported no memory leaks - Free Pascal 2.6.2, however, it shows a leak if the TBytes value is passed to a method with a parameter of type Pointer .

The following memory leak code:

 program project1; {$mode delphi} uses SysUtils; function ToBytes(const AValue: AnsiString): TBytes; begin SetLength(Result, Length(AValue)); // <-- leak (ine 10) if Length(AValue) > 0 then Move(AValue[1], Result[0], Length(AValue)); end; procedure Send(P: Pointer); begin end; begin Send(ToBytes('test')); SetHeapTraceOutput('heaptrace.log'); end. 

Memory Leak Report:

 Call trace for block $001C5CC0 size 12 $00401586 TOBYTES, line 10 of project1.lpr $00401622 main, line 21 of project1.lpr 

If I change the send method to accept an argument of type TBytes, the memory leak will disappear.

+7
memory-leaks freepascal compiler-bug fpc
source share
3 answers

This is a compiler error. The managed type TBytes has a calculated lifetime. The compiler must create an implicit local variable that is assigned the array returned by ToBytes . You will need to get around this while maintaining an explicit local:

 var Tmp: TBytes; .... Tmp := ToBytes(...); Send(Tmp); 
+4
source share

This is probably not the mistake you are thinking about. FPC heap tracing knew problems with tracking rates (and automatic types in general) in main programs (main .dpr begin..end).

Move the code to the procedure and call it from the main begin..end. and you will see that the leak disappears.

This is because the general structure of the main program is similar to

 begin initializeunits(); // procedure call inserted by the compiler <actual mainprogram statements> finalizeunits(); // procedure call inserted by the compiler end. 

with the release of the main programmatic pace taking place at the end. after finalizeunits, which completes heaptracking. (even if this is the first block, it is still only a unit). Therefore heaptrc skips this.

+1
source share

Functions that return things that potentially contain a lot of memory make me squeamish. It may be just a feeling or a personal preference, but it removes control over the allocation of memory. Similar things are said about a function that returns (just built) TStringList instances, it is also advisable to pass a pointer to the TStrings object there and let the caller control the object's lifetime.

Here I would advise using the var parameter for all operations on TBytes and forcing the caller to provide an instance to work with. If you create a complex application and should look for where you can improve performance, think about it again and see if you can recycle TBytes instances with similar content or length. An important feature of the Delphi string system is that you do reference counting and copy-to-write backstage, providing this performance boost when your application processes many (similar) strings.

0
source share

All Articles