Jump to content
terran

Memory leak on TParallel.For

Recommended Posts

Memory leak on TParallel.For

 

it happens on empty TParallel.For

    TParallel.For(0, 10, procedure(yy:integer)
    begin
    for var xx:=0 to 10 do
      begin

      end;
    end);
Quote

This application has leaked memory. The leaks ordered by size are:

8: 54 x System.TObject
24: 27 x System.SyncObjs.TLightweightEvent
32: 27 x System.Threading.TWorkStealingQueue<System.Threading.TThreadPool.IThreadPoolWorkItem>
52: 1 x System.Threading.TThreadPool.TThreadPoolMonitor
68: 27 x System.Threading.TThreadPool.TQueueWorkerThread
74: 1 x UnicodeString
136: 27 x Unknown
176: 1 x UnicodeString

No my code in stack.

 

No "minimal (non)-reproducible example" can be done. It's a DLL, and it does its job inside a third-party application.

 

 

 

MemoryManager_EventLog.txt

Edited by terran

Share this post


Link to post

I don't have an answer, just one to do about thing this

43 minutes ago, terran said:

No my code in stack.

 

No "minimal (non)-reproducible example" can be done. It's a DLL, and it does its job inside a third-party application.

Add a fake (not used) TMyObject to your code, create it inside that loop you are doubting, then don't free it !

See if the report is consistent and reliable, with 11 leaked TMyObject.

 

This might save time.

Share this post


Link to post
11 hours ago, Dmitry Arefiev said:

What is the Delphi version ?

12

Share this post


Link to post

@terran i see you updated you post with a log 

 

Yes that log does shows memory leaks, and you didn't do what i asked for and suggested, but yet more information is needed to pin point the problem, i do understand you can't share codes,

But as curtesy and respect for our time as yours, read what people write you and if you don't understand their reasons and logic, then you can ask, you might learn something or two.

 

So here what i see with the little provided:

I put your log in Notepad++ and searched for all the occurrences of "The allocation number is", the result is

	Line   28: The allocation number is: 3155
	Line   60: The allocation number is: 504725
	Line   92: The allocation number is: 504689
	Line  124: The allocation number is: 504673
	Line  156: The allocation number is: 504650
	Line  188: The allocation number is: 504623
	Line  220: The allocation number is: 504604
	Line  252: The allocation number is: 502198
	Line  284: The allocation number is: 486818
	Line  316: The allocation number is: 486791
	Line  348: The allocation number is: 486093
	Line  380: The allocation number is: 504750
	Line  412: The allocation number is: 504747
	Line  444: The allocation number is: 504733
	Line  476: The allocation number is: 504727
	Line  508: The allocation number is: 504694
	Line  540: The allocation number is: 504690
	Line  572: The allocation number is: 504678
	Line  604: The allocation number is: 504674
	Line  636: The allocation number is: 504656
	Line  668: The allocation number is: 504652
	Line  700: The allocation number is: 504630
	Line  732: The allocation number is: 504625
	Line  764: The allocation number is: 504608
	Line  796: The allocation number is: 504605
	Line  828: The allocation number is: 502202
	Line  860: The allocation number is: 502199
	Line  892: The allocation number is: 486839
	Line  924: The allocation number is: 486795
	Line  956: The allocation number is: 486792
	Line  988: The allocation number is: 486099
	Line 1020: The allocation number is: 486094
	Line 1052: The allocation number is: 486819
	Line 1084: The allocation number is: 484903
	Line 1116: The allocation number is: 484900
	Line 1148: The allocation number is: 2221
	Line 1180: The allocation number is: 2293
	Line 1212: The allocation number is: 2127
	Line 1244: The allocation number is: 2087
	Line 1276: The allocation number is: 2047
	Line 1308: The allocation number is: 504746
	Line 1340: The allocation number is: 2018
	Line 1372: The allocation number is: 1971
	Line 1404: The allocation number is: 3168
	Line 1436: The allocation number is: 1944
	Line 1468: The allocation number is: 1896
	Line 1500: The allocation number is: 1873
	Line 1532: The allocation number is: 1860
	Line 1564: The allocation number is: 1888
	Line 1596: The allocation number is: 1850
	Line 1628: The allocation number is: 484899
	Line 1660: The allocation number is: 1902
	Line 1694: The allocation number is: 504748
	Line 1728: The allocation number is: 504729
	Line 1762: The allocation number is: 504691
	Line 1796: The allocation number is: 504675
	Line 1830: The allocation number is: 504653
	Line 1864: The allocation number is: 504627
	Line 1898: The allocation number is: 504606
	Line 1932: The allocation number is: 502200
	Line 1966: The allocation number is: 486829
	Line 2000: The allocation number is: 486793
	Line 2034: The allocation number is: 486096
	Line 2068: The allocation number is: 3170
	Line 2102: The allocation number is: 484901
	Line 2136: The allocation number is: 3157
	Line 2170: The allocation number is: 2295
	Line 2204: The allocation number is: 2223
	Line 2238: The allocation number is: 2131
	Line 2272: The allocation number is: 2020
	Line 2306: The allocation number is: 2090
	Line 2340: The allocation number is: 1946
	Line 2374: The allocation number is: 1974
	Line 2408: The allocation number is: 1899
	Line 2442: The allocation number is: 2049
	Line 2476: The allocation number is: 1875
	Line 2510: The allocation number is: 1890
	Line 2544: The allocation number is: 1862
	Line 2578: The allocation number is: 1853
	Line 2612: The allocation number is: 1989
	Line 2654: The allocation number is: 3169
	Line 2686: The allocation number is: 2297
	Line 2718: The allocation number is: 2225
	Line 2750: The allocation number is: 2294
	Line 2782: The allocation number is: 2136
	Line 2814: The allocation number is: 2222
	Line 2846: The allocation number is: 2092
	Line 2878: The allocation number is: 2129
	Line 2910: The allocation number is: 2051
	Line 2942: The allocation number is: 2088
	Line 2974: The allocation number is: 3173
	Line 3006: The allocation number is: 2022
	Line 3038: The allocation number is: 2019
	Line 3070: The allocation number is: 1976
	Line 3102: The allocation number is: 2048
	Line 3134: The allocation number is: 3159
	Line 3166: The allocation number is: 1948
	Line 3198: The allocation number is: 1972
	Line 3230: The allocation number is: 3156
	Line 3262: The allocation number is: 1901
	Line 3294: The allocation number is: 1945
	Line 3326: The allocation number is: 1892
	Line 3358: The allocation number is: 1897
	Line 3390: The allocation number is: 1877
	Line 3422: The allocation number is: 1889
	Line 3454: The allocation number is: 1864
	Line 3486: The allocation number is: 1874
	Line 3518: The allocation number is: 1855
	Line 3550: The allocation number is: 1851
	Line 3582: The allocation number is: 1861
	Line 3614: The allocation number is: 504739
	Line 3650: The allocation number is: 504703
	Line 3686: The allocation number is: 504687
	Line 3722: The allocation number is: 504661
	Line 3758: The allocation number is: 504635
	Line 3794: The allocation number is: 502167
	Line 3830: The allocation number is: 486073
	Line 3866: The allocation number is: 486801
	Line 3902: The allocation number is: 486575
	Line 3938: The allocation number is: 504614
	Line 3974: The allocation number is: 3164
	Line 4010: The allocation number is: 2174
	Line 4046: The allocation number is: 3113
	Line 4082: The allocation number is: 2065
	Line 4118: The allocation number is: 2107
	Line 4154: The allocation number is: 2236
	Line 4190: The allocation number is: 1997
	Line 4226: The allocation number is: 2031
	Line 4262: The allocation number is: 1960
	Line 4298: The allocation number is: 1934
	Line 4334: The allocation number is: 1893
	Line 4365: The allocation number is: 1978
	Line 4401: The allocation number is: 1865
	Line 4437: The allocation number is: 1878
	Line 4473: The allocation number is: 1857
	Line 4509: The allocation number is: 1848
	Line 4545: The allocation number is: 484882
	Line 4581: The allocation number is: 504587
	Line 4617: The allocation number is: 504749
	Line 4657: The allocation number is: 504731
	Line 4697: The allocation number is: 504692
	Line 4737: The allocation number is: 504676
	Line 4777: The allocation number is: 504655
	Line 4817: The allocation number is: 504629
	Line 4857: The allocation number is: 504607
	Line 4897: The allocation number is: 502201
	Line 4937: The allocation number is: 486836
	Line 4977: The allocation number is: 486794
	Line 5017: The allocation number is: 484902
	Line 5057: The allocation number is: 486098
	Line 5097: The allocation number is: 3171
	Line 5137: The allocation number is: 3158
	Line 5177: The allocation number is: 2296
	Line 5217: The allocation number is: 2224
	Line 5257: The allocation number is: 2133
	Line 5297: The allocation number is: 2091
	Line 5337: The allocation number is: 2050
	Line 5377: The allocation number is: 2021
	Line 5417: The allocation number is: 1975
	Line 5457: The allocation number is: 1947
	Line 5497: The allocation number is: 1900
	Line 5537: The allocation number is: 1891
	Line 5577: The allocation number is: 1876
	Line 5617: The allocation number is: 1863
	Line 5657: The allocation number is: 1854

This shows two group of leaks, one group happen very early, while the other was very late, both group are condensed, meaning they do happen on specific event.

 

I followed what i think is the first (the oldest reported leak) with number 1848, and here is it

--------------------------------2024-09-02 17:00:36--------------------------------
A memory block has been leaked. The size is: 68

This block was allocated by thread 0xA44, and the stack trace (return addresses) at the time was:
0542E4D2 [fastmm5.pas][FastMM5][FastMM_DebugGetMem$qqri][7820]
054170D2 [System.pas][System][@GetMem$qqri][4962]
05418F9B [System.pas][System][TObject.NewInstance][18331]
0541969E [System.pas][System][@ClassCreate$qqrpvzc][19661]
05517233 [System.Threading.pas][System.Threading][Threading.TThreadPool.TQueueWorkerThread.Create][3479]
0541970C [System.pas][System][@AfterConstruction$qqrxp14System.TObject][19710]
05516998 [System.Threading.pas][System.Threading][Threading.TThreadPool.CreateWorkerThread][3223]
05516B19 [System.Threading.pas][System.Threading][Threading.TThreadPool.GrowWorkerPool][3269]
05516E1F [System.Threading.pas][System.Threading][Threading.TThreadPool.QueueWorkItem][3357]
05513D9B [System.Threading.pas][System.Threading][Threading.TTask.QueueEvents][2715]
055145C1 [System.Threading.pas][System.Threading][Threading.TParallel.TReplicableTask.QueueEvents][2972]
0551419B [System.Threading.pas][System.Threading][Threading.TTask.Start][2779]
05510F1A [System.Threading.pas][System.Threading][Threading.TParallel.ForWorker][1483]
056D8CF2 [ImageCompare.dpr][ImageCompare][ResizeCanvas$qqrp33Imagingcanvases.TFastARGB32Canvasp30Imagingcanvases.TImagingCanvasiiii][1069]
05653BA6 [ImagingCanvases.pas][ImagingCanvases][TImagingCanvas.ResetClipRect][954]
056CA19D [Imaging.pas][Imaging][GetImageFormatInfo$qqr25Imagingtypes.TImageFormatr29Imagingtypes.TImageFormatInfo][2812]
05653B76 [ImagingCanvases.pas][ImagingCanvases][TImagingCanvas.UpdateCanvasState][949]
056C432E [Imaging.pas][Imaging][TestImage$qqrrx23Imagingtypes.TImageData][921]
056D97E9 [ImageCompare.dpr][ImageCompare][TProcessFile.GetdHash$qqrr22Imagecompare.TLastInfox20System.UnicodeStringiii][1200]
77911B2C [Unknown function at RtlpNtEnumerateSubKey]

The block is currently used for an object of class: System.Threading.TThreadPool.TQueueWorkerThread

The allocation number is: 1848

Current memory dump of 76 bytes starting at pointer address 72AE3A0:
AC 3C 50 05 A4 9E 00 00 CC 03 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 20 FB 2C 07 40 4F 21 07 40 EB 22 07 64 FB 2C 07 68 FB 2C 07 00 CB 27 07
00 00 00 00 D4 2F 2C 8D D2 E4 42 05
.  <  P  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
.  .  .  .  .  .  .  .  .  .  ,  .  @  O  !  .  @  .  "  .  d  .  ,  .  h  .  ,  .  .  .  '  .
.  .  .  .  .  /  ,  .  .  .  B  .

Now this proof you are wrong about none of your code is involved !

All start in your ImageCompare.dpr, so more information is needed here,

Is that ImageCompare.dpr belongs to a DLL or an EXE ?

 

Another thing, is there any thing prohibited you from do what i suggested about deliberately invoked leaks ?

Again and for the last time, put TMyObjectX before such loops you pasted above, replace X with a number (1,2,3..) so they can be named and recognized in the log, and put this simple line in the loop "TMyObject.Create;" no variable, no thing, this is enough to cause a leak to report.

 

Depending on the number of reported leaks for these TMyObject1, TMyObject2.... you and we can see a little more, because in your first post there was very interesting numbers 27 and 54, yet the loop is 11 !

This must be addressed also, to get the bigger picture or at least identify a method to catch and categorize the problem, is it a Compiler/RTL bug or some mishandling code.

 

Another thing, Why ImageCompare.dpr does show in the log to begin with ? in case it is a DLL then you must not initialize long process or an even more dangerous process like multithreading, when the thread is Loaded/Attcached, like such process that depend on and identify the calling thread as main one, the calling thread here (in case with DLL) is an OS one that will be created and will be destroyed by the OS, and this will confuse your code with the Process Main Thread, causing all sort of problem.

 

And good luck !

 

Share this post


Link to post
On 9/2/2024 at 9:18 AM, terran said:

Memory leak on TParallel.For

...

No "minimal (non)-reproducible example" can be done. It's a DLL, and it does its job inside a third-party application.

I wonder if this is a false positive?  The log shows a thread pool is involved. Makes me wonder if the pool threads are simply still running when the leak report is generated.  You have to make sure everything is shutdown first before the memory manager is cleaned up.

Share this post


Link to post

Probably it has exception in System.Threading that is not passed to the program, and the worker threads are waiting in a deadlock. That's all I know.

 

Possible place somewhere here (System.Threading, 3535):

                Signaled := TMonitor.Wait(ThreadPool.FQueue, WaitTime) and not ThreadPool.FShutdown;

 

Possible stack somewhere here:

:7785f8d1 ntdll.ZwWaitForSingleObject + 0x15
:75e51194 kernel32.WaitForSingleObjectEx + 0x43
:75e51148 kernel32.WaitForSingleObject + 0x12
System.SysUtils.WaitForSyncWaitObj(???,???)
System.SysUtils.WaitOrSignalObj(???,$9C40,???)
System.TMonitor.Wait($73E9040,40000)
System.TMonitor.Wait(???,40000)
System.Threading.TThreadPool.TQueueWorkerThread.Execute
System.Classes.ThreadProc($728E3A0)
System.ThreadWrapper($728A850)
:75e5343d kernel32.BaseThreadInitThunk + 0x12
:77879812 ntdll.RtlInitializeExceptionChain + 0x63
:778797e5 ntdll.RtlInitializeExceptionChain + 0x36

That's all I know.

 

On 9/3/2024 at 8:59 AM, Kas Ob. said:

Is that ImageCompare.dpr belongs to a DLL or an EXE ?

DLL

 

It is not used when thread loaded/unloaded.

 

If I didn't answer something, then it did not help, or I didn't understand. That's all I know.

 

On 9/3/2024 at 8:59 AM, Kas Ob. said:

Now this proof you are wrong about none of your code is involved !

1. No my code after start of thread.

2. It happens (even) on empty loop.

Edited by terran

Share this post


Link to post

1) How many loop are there in the code in that DLL ? and many iteration being executed ? and compare that to the reported leaks numbers ?

2) Empty loops does produce leaks ? this means broken logic in TThreadPool, yet doesn't mean it is buggy yet, it could be MM, at least try FastMM4 for both EXE and DLL, make sure you are using the same MM.

3) Not bad idea to use the manually induced leaks, this will consolidate the numbers, like i explained above, you should make sure of consistency of the report, if you have more than one loop.

4) in my opinion, TThreadPoolMonitor is the one behind all these leaks, this easily can happen if it is was locked and corrupted or overwritten, that is your target and the direct cause in this bug hunt, it is reported as leak in your log, and as you pointed to.

 

8 hours ago, terran said:

1. No my code after start of thread.

Yet unless someone can confirm and reproduce it, i am inclined to assume your project environment (setup) is responsible for it. 

8 hours ago, terran said:

2. It happens (even) on empty loop.

Unfortunately, that is good news, and means replicating or reproducing a smaller and stripped project (the smallest new project) to reproduce this bug is feasible, so please try ! 

 

Just one thought, lets imagine one thread belongs to TThreadPool was stuck/frozen/looping, how one thread being would affect the pool exiting and cleaning after the threads, does its position affect the pool behavior, like if it was the first, last or in the middle... I don't have an answer for this, so i suggest to dump pall the threads on exit, also don't know how madshi, but i know eurekalog can do this and triggered by hand or by option and manually induced an exception, in any case try to dump all the threads and their stacks to see if there is a thread is still do something or simply unhinged somewhere.

The best way to do this is to introduce any unit to the project that has finalization and here you will trigger the threads dump (to get all threads stacks), make sure this unit is the highest place in the dpr uses clause, right after MM, and of course right after the exception tool you will use.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×