Jump to content
RussellW

Runtime Error on Closing with ScaleMM2 Memory Manager

Recommended Posts

I have an application using IOmniBackgroundWorker and I'm using ScaleMM2.

 

I had a memory leak issue in the interfaced object passed to the WorkItem and while that existed I had no issues when I shut down the application.

 

However, having fixed that issue (circular Interface issue fixed by declaring the field as [weak]) I now get a runtime error when I shut down the application. If I use the standard Delphi Memory Manager I don't get this exception.

 

Any ideas about tracking this down?

Share this post


Link to post

Try to minimize the problem. Extract the problematic code from the application and try to reproduce. Or disable parts of the code which could relate to the problem and check if it went away. 

Share this post


Link to post

In my experience and tests, the latest FastMM4 has various leak related issues, some of them are quite bad with the newer versions of Delphi that don't exist with the built-in memory manager which is also a subset of FastMM.  Most of the memory managers haven't been actively worked on in years and I doubt their ability to properly handle many scenarios.

Share this post


Link to post

FastMM4 works perfectly and has no leaks as far as I know.  We are using FastMM4 in Delphi applications that run 24/7 for years at the time and it works just fine.

 

That holds for the latest FastMM from https://github.com/pleriche/FastMM4. I have no idea how built-in FastMM works.

 

One should just be careful when running FastMM4 with /dFullDebugMode. In this mode, FastMM never returns memory to the operating system and your code can run out of memory. This is a feature, not a bug.

  • Thanks 1

Share this post


Link to post

Interesting. This error occurs with FastMM4, BrainMM and ScaleMM2 but not with the FastMM default in Delphi. However, at the end of the ScaleMM2 pas file there is this:

finalization
  {$if CompilerVersion < 23}
  // issue 6: Delphi XE2 has annoying bug when using SetLocaleOverride -> AV in finalization of System.pas due to freemem(PreferredLanguagesOverride)
  // So in case of Delphi XE and lower, we use the normal method
  ScaleMMUninstall;
{$ifend}

Now if I call ScaleMMUninstall irrespective of Compiler (in this case I'm using Tokyo) then my runtime error when the app is closed goes away.

Share this post


Link to post
Posted (edited)

The problem is not any 3rd party MM but the fact that some pieces in the RTL are deallocated within System.pas finalization which takes place after detaching/finalizing any 3rd party MM (if that one does something in its finalization block as posted in the previous post). And then it tries to give back memory to the system that it orginally had from the already unloaded/detached 3rd party MM.

 

There are various fixes in the RTL (I don't remember which version they did that in) that use SysGetMem/SysFreeMem to bypass the pluggable memory manager API. It can very well be the case they missed something or you are using a version that does not have them yet.

Edited by Stefan Glienke
  • Like 1

Share this post


Link to post
Posted (edited)
20 minutes ago, Stefan Glienke said:

The problem is not any 3rd party MM but the fact that some pieces in the RTL are deallocated within System.pas finalization which takes place after detaching/finalizing any 3rd party MM 

Out of curiosity, what are you all using to determine you are leaking or not?  Let's assume we ignore System.pas related things.  Have you compared the results of a tool like the Deleaker using the base memory manager with a large project vs. Deleaker with FastMM4 enabled (without full debug mode) or any other memory manager?

Edited by Allen@Grijjy
minor

Share this post


Link to post
Posted (edited)

Attached is the smallest example I could make of a leak (it leaks roughly 1MB) that only occurs in FastMM4 (latest edition) with FullDebugMode disabled but does not occur with the default memory manager of Delphi 10.3.  To test it, just compare it with FastMM4 commented/uncommented in the .dpr.  You will need some external leak analysis tool like this one, for example,

https://www.deleaker.com

 

I honestly would like to understand what is happening here because I have also used FastMM over the years in numerous projects, but I found a few issues like this one and a couple of others related to reference counted interface de-allocations.

 

Note: I am aware that FastMM4's leak checker doesn't show any leaks, but like I said previously, I don't trust it to analyze itself.

LeakExample.zip

Edited by Allen@Grijjy

Share this post


Link to post

I use MadExcept for in app leak checking. I seem to get them on TMemIniFile a bit.

Share this post


Link to post
Posted (edited)

FastMM4 FullDebug in a debug build of our application - LeakCheck in unit and integration tests

 

If any third party leak analysis tool claims that FastMM has a memory leak it probably will tell you the call stack of where it comes from and you will be able to find it.

Also are you aware that there is RegisterExpectedMemoryLeak function that the third party tool might not be aware of and has a false positive?

 

As for Deleaker - I think that tool and me won't become friends. UI is irritating and if its burning 100% of my CPU for minutes while triggering a million werfault.exe processes that it supresses until I press cancel to find some memory allocation leaks from that simple program I can't imagine what it will do when I let it run for a real application. "Sorry, but's a no from me"

Edited by Stefan Glienke
  • Like 2

Share this post


Link to post
Posted (edited)
3 hours ago, Stefan Glienke said:

If any third party leak analysis tool claims that FastMM has a memory leak it probably will tell you the call stack of where it comes from and you will be able to find it.

Also are you aware that there is RegisterExpectedMemoryLeak function that the third party tool might not be aware of and has a false positive?

The example I made is trivial.  It expands a queue, so the size of the leak is directly proportional to the number of records you en-queue.  Even if you destroy the queue, the leak persists.  I am aware of RegisterExpectedMemoryLeak function.

 

The call stack shows the problem comes from the Collections.TListHelper.InternalSetCapacity in Delphi's collections unit, that eventually calls the ReallocMem routine:

LeakExample.exe!@ReallocMem$qqrrpvi Line 4900 004070b8
LeakExample.exe!DynArraySetLength$qqrrpvpvipi Line 35920 + 0x5 bytes 0040c466
LeakExample.exe!Generics.Collections.TListHelper.InternalSetCapacity Line 4489 + 0x9 bytes 004eb6f1
 

In the example I provided the actual collection is a queue of records that is created and destroyed.  However when the queue grows, FastMM internally calls FastReallocMem to expand and internally determines it's a large block reallocation.  If I simply redirect the ReallocMem routine back to SysReallocMem inside of FastMM, everything deallocates properly.  Like you said, it could be a flaw in this tool, but the problem doesn't happen with Delphi's built in memory manager.  It also doesn't happen if I change FastMM's source to simply call SysReallocMem immediately upon calling FastReallocMem.  It also doesn't happen with numerous other data types, just collections, specifically queues of records.

Edited by Allen@Grijjy
  • Like 1

Share this post


Link to post

I have just tried my app (64Bit, 16 threads) with ScaleMM2 again, and get this exception on the first batch I run, but not on shutdown as the app is still running:

exception number   : 1
exception class    : EInvalidPointer
exception message  : Invalid pointer operation.

main thread ($163c):
0041ecf3 +053 PlustNetProcess.LeakTest2.exe smmLargeMemory   125 +13 TLargeMemThreadManager.FreeMem
013f6c57 +087 PlustNetProcess.LeakTest2.exe DSiWin32        6175 +15 DSiClassWndProc
7ffa03bf +000 user32.dll                                             DispatchMessageW
007d206e +12e PlustNetProcess.LeakTest2.exe Vcl.Forms                TApplication.ProcessMessage
007d20e3 +013 PlustNetProcess.LeakTest2.exe Vcl.Forms                TApplication.HandleMessage
007d2531 +0e1 PlustNetProcess.LeakTest2.exe Vcl.Forms                TApplication.Run
01fb3e27 +147 PlustNetProcess.LeakTest2.exe PlustNetProcess  116 +17 initialization
7ffa0379 +020 KERNEL32.DLL                                           BaseThreadInitThunk
7ffa058f +032 ntdll.dll                                              RtlUserThreadStart

I tried IntelTBB (Single allocated thread) and got an AV on closedown as did BrainMM and FastMM. The only one that doesn't is the one that ships with Delphi, which doesn't give me the speed that is needed.

 

Any ideas? I guess I could try a simple threaded app to see if that throws up anything.

 

 

 

 

 

 

 

 

Share this post


Link to post

The FastMM4 raises the error as a call to a memory function after FastMM4 has been unloaded. There is an option in the inc file to not raise that. 

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
×