Possible Memory Leak in TThread.Synchronize

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Possible Memory Leak in TThread.Synchronize

Tony Whyman
I have been investigating a possible memory leak in a multi-threading
Lazarus program compiled with 3.0.4 where the stack trace with heaptrc
shows:

Heap dump by heaptrc unit
7014 memory blocks allocated : 131978472/131992352
7004 memory blocks freed     : 114543216/114557096
10 unfreed memory blocks : 17435256
True heap size : 19267584
True free heap : 1831200
Should be : 1831048
Call trace for block $00007FFFE2A9D0C0 size 96
   $000000000043B31A line 354 of ../inc/heap.inc
   $0000000000450FE8 line 888 of ../unix/cthreads.pp
   $000000000043DB9F line 294 of ../inc/thread.inc
   $00000000004AE6B4 line 322 of ../objpas/classes/classes.inc
   $00000000004AE754 line 344 of ../objpas/classes/classes.inc
   $00000000004AE7F0 line 357 of ../objpas/classes/classes.inc
   ....

Line 322 of classes.inc reads:

     FSynchronizeEntry^.SyncEvent := RtlEventCreate;

Hence the implication is that the SyncEvent is not being disposed of
correctly. Later on TThread.DoneSynchronizeEvent reads

procedure TThread.DoneSynchronizeEvent;
   begin
     if not Assigned(FSynchronizeEntry) then
       Exit;

     RtlEventDestroy(FSynchronizeEntry^.SyncEvent);
     Dispose(FSynchronizeEntry);
     FSynchronizeEntry := Nil;
   end;

So no problem here it seems. However, investigating further, this is not
the only place that a SynchronizeEvent is disposed of. At line 379 of
classes.inc we see:

function CheckSynchronize(...)

and this ends with:

     else
       begin
       { for Queue entries we dispose the entry and raise the exception }
       Dispose(tmpentry);
       if Assigned(exceptobj) then
         raise exceptobj;
       end;
     tmpentry := PopThreadQueueHead;
     end;

The line "Dispose(tmpentry);" also disposes of a SynchronizeEvent but,
unlike TThread.DoneSynchronizeEvent, there is no RtlEventDestroy.

Am I correct in pointing the finger here for the memory leak?

Tony Whyman

MWA


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Possible Memory Leak in TThread.Synchronize

Michael Van Canneyt


On Wed, 3 Jan 2018, Tony Whyman wrote:

>
> The line "Dispose(tmpentry);" also disposes of a SynchronizeEvent but,
> unlike TThread.DoneSynchronizeEvent, there is no RtlEventDestroy.
>
> Am I correct in pointing the finger here for the memory leak?

I doubt it, since AFAIK the RTL event is a OS object, and as such is not allocated on the
heap ?

Michael.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Possible Memory Leak in TThread.Synchronize

Tony Whyman
Thanks, I found the problem - the thread was not being destroyed
correctly on completion and this manifested itself in what looked like a
weird memory leak.


On 03/01/18 11:49, Michael Van Canneyt wrote:

>
>
> On Wed, 3 Jan 2018, Tony Whyman wrote:
>
>>
>> The line "Dispose(tmpentry);" also disposes of a SynchronizeEvent
>> but, unlike TThread.DoneSynchronizeEvent, there is no RtlEventDestroy.
>>
>> Am I correct in pointing the finger here for the memory leak?
>
> I doubt it, since AFAIK the RTL event is a OS object, and as such is
> not allocated on the
> heap ?
>
> Michael.
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
>

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Possible Memory Leak in TThread.Synchronize

Free Pascal - General mailing list
In reply to this post by Tony Whyman
Am 03.01.2018 12:32 schrieb "Tony Whyman" <[hidden email]>:

function CheckSynchronize(...)

and this ends with:

    else
      begin
      { for Queue entries we dispose the entry and raise the exception }
      Dispose(tmpentry);
      if Assigned(exceptobj) then
        raise exceptobj;
      end;
    tmpentry := PopThreadQueueHead;
    end;

The line "Dispose(tmpentry);" also disposes of a SynchronizeEvent but, unlike TThread.DoneSynchronizeEvent, there is no RtlEventDestroy.

Am I correct in pointing the finger here for the memory leak?

I know you already found your problem, but nevertheless as explanation: this code is only reached by asynchronously added events (TThread.Queue()) and there no event is needed, this none is freed or even allocated. 

Regards, 
Sven 

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal