RegisterExpectedMemoryLeak

delphi package - automated exception handling
Post Reply
rossmcm
Posts: 74
Joined: Thu Jun 09, 2005 2:05 am
Contact:

RegisterExpectedMemoryLeak

Post by rossmcm »

I'm a bit hazy on the relationship between MadExcept's memory leak reporting and FastMM4. FastMM has the routine RegisterExpectedMemoryLeak to announce known or innocuous memory leaks so that reports aren't generated if there are no memory leaks apart from those ones.

Is there an equivalent function in ME? (I can't search for "RegisterExpectedMemoryLeak" - it's too long!).

Can I still use the FastMM one (it doesn't seem to work)?

Thanks,
R
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: RegisterExpectedMemoryLeak

Post by madshi »

madExcept has a function called "ThisIsNoLeak()". See here:

http://help.madshi.net/madExceptUnit.htm#ThisIsNoLeak
rossmcm
Posts: 74
Joined: Thu Jun 09, 2005 2:05 am
Contact:

Re: RegisterExpectedMemoryLeak

Post by rossmcm »

Thanks Mathias, The FastMM version can be called with a class identifier and count, e.g.:

Code: Select all

RegisterExpectedMemoryLeak (TBitmap, 3) ;
which allows 3 instances of TBitmap to be allocated and not freed without complaint. Being able to specify the memory leaks by class is useful because it means I don't have find where they occur, and I don't need to modify the source where they occur, which is better when it is in a library.

For example, I know that Indy leaks a TIdThreadSafeInteger and 2 of TIdCriticalSection each time my app runs, but this is known about and inconsequential - so I have this at the start of my main program:

Code: Select all

RegisterExpectedMemoryLeak (TIdThreadSafeInteger, 1) ;      
RegisterExpectedMemoryLeak (TIdCriticalSection, 2) ;
How would I use ThisIsNoLeak to suppress the report here? Do you support this? (or plan to?).
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: RegisterExpectedMemoryLeak

Post by madshi »

This is currently not supported. It's not a bad idea, but I'm wondering how it would work if there are real leaks with the same class? E.g. what happens if there are 4 TBitmap leaks? Are all 4 shown then? Or are the "first" 3 ignored?
rossmcm
Posts: 74
Joined: Thu Jun 09, 2005 2:05 am
Contact:

Re: RegisterExpectedMemoryLeak

Post by rossmcm »

I guess that you could expect any memory leaked in this fashion would likely be allocated in the a library unit initialisation, i.e. before your program had started allocating memory. So if you had

Code: Select all

ThisIsNoLeak (TBitmap, 4) ;
you could store the class identifying info and a counter which you would initialise to 4. Every time a TBitmap is allocated the counter would be decremented and when the counter reaches zero assume that all of the class instances that need to be ignored have been allocated and start logging that class from then on. It wouldn't be foolproof but would still be useful in a lot of cases.
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: RegisterExpectedMemoryLeak

Post by madshi »

Wouldn't it be more useful to hide the expected leaks only if there are no additional leaks, and to show all 4 TBitmap leaks, if there are more than expected? I fear that when there are 4 leaks instead of the expected 3, we can't know for sure if the expected leaks are really the first 3. They might be in most cases, but that doesn't always have to be true. If it's not true, we would actually see one expected leak and the real leak would be hidden...
rossmcm
Posts: 74
Joined: Thu Jun 09, 2005 2:05 am
Contact:

Re: RegisterExpectedMemoryLeak

Post by rossmcm »

Yes indeed. In fact that's exactly how FastMM does it. If the only memory leaks it detects are ones notified to it, you don't get any report, otherwise you get all leaks reported.
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: RegisterExpectedMemoryLeak

Post by madshi »

Ok, I'll add this to my to do list.
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: RegisterExpectedMemoryLeak

Post by madshi »

Implemented in this build:

http://madshi.net/madCollectionBeta.exe (installer 2.7.7.15)

Code: Select all

// Call this API to hide expected object leaks.
// If more objects are leaked than expected, all will be shown.
function HideLeak (someClass: TClass; count: integer) : boolean; overload;
rossmcm
Posts: 74
Joined: Thu Jun 09, 2005 2:05 am
Contact:

Re: RegisterExpectedMemoryLeak

Post by rossmcm »

Hi Mathias,

I have 4.0.9 installed but am getting some curious results with HideLeak. Could you please comment.

Here is the report from an IDE compile and run (D2007) of an application with no calls to HideLeak at the start of the DPR file.

Image

The two leaks from TIdThreadSafeInteger, TIdCriticalSection are from Indy, and are unavoidable unless we want to mess with the sources. They are the ones I am wanting hide.
Here is the report with the following added:

Code: Select all

MadExcept.HideLeak (TIdThreadSafeInteger, 1) ;
MadExcept.HideLeak (TIdCriticalSection, 1) ;
Image

and with the following...

Code: Select all

MadExcept.HideLeak (TIdThreadSafeInteger, 1) ;
MadExcept.HideLeak (TIdCriticalSection, 2) ;
Image

So I can supress the TIdThreadSafeInteger but not the TIdCriticalSection.

Also, the other reported leaks of thread handles have call stacks that aren't in my application sources - might these be related to the Indy leaks?
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: RegisterExpectedMemoryLeak

Post by madshi »

rossmcm wrote:So I can supress the TIdThreadSafeInteger but not the TIdCriticalSection.
Hmmmm... The leak checker handles TCriticalSection related objects differently. Is the problem fixed in the following build?

http://madshi.net/madCollectionBeta.exe (installer 2.7.8.1)
rossmcm wrote:Also, the other reported leaks of thread handles have call stacks that aren't in my application sources - might these be related to the Indy leaks?
How should I know - without seeing the callstacks of those leaks? My telepathic powers only work on Sundays...
rossmcm
Posts: 74
Joined: Thu Jun 09, 2005 2:05 am
Contact:

Re: RegisterExpectedMemoryLeak

Post by rossmcm »

How should I know - without seeing the callstacks of those leaks? My telepathic powers only work on Sundays...
Sorry Mathias, I thought it was Sunday when I wrote the post... ;)

I have installed the Dec 5 Beta and repeated the tests. With no calls to HideLeak:

Image

With:

Code: Select all

MadExcept.HideLeak (TIdThreadSafeInteger, 1) ;
MadExcept.HideLeak (TIdCriticalSection, 1) ;
I now get the following:

Image

Image

Image

...so it looks as if you have successfully dealt with the TIdCriticalSection leak. Many thanks. As to the remaining leaks, the last one I think I have found. AfSafeSync is part of the AsyncFree serial COM port component:

Code: Select all

initialization
  SyncMutex := CreateMutex(nil, False, nil);      <------------------------------------------------- line 394
  UniqueIDGenerator := 0;
finalization
  ReleaseSyncHandler;
end.
ReleaseSyncHandler called from the finalization doesn't seem to free the Mutex:

Code: Select all

procedure ReleaseSyncHandler;
begin
  if HandlerAllocated then
  begin
    HandlerAllocated := False;
    DestroyWindow(SyncWnd);
    FreeMem(SyncSlots);
  end;
end;
So I added a call to the finalization clause of the unit:

Code: Select all

finalization
  ReleaseSyncHandler;
  CloseHandle (SyncMutex) ;  
 end.
and that seems to have nailed that one. The remaining two leaks I have no idea.

P.S. I should mention that there is feature of MadExcept that has an advantage over FastMM's leak reporting: When FastMM generates the leak report, it does so by calling the routine from your application's program, whereas MadExcept seems to do it by spawning a separate viewer task. This means that the application EXE is released back to the IDE straight away and you can accumulate more than one viewer and leave them displayed while you recompile.
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: RegisterExpectedMemoryLeak

Post by madshi »

rossmcm wrote:The remaining two leaks I have no idea.
The first one is not clear, the callstack is not giving us enough information. However, the middle one looks clear to me. It seems that msxmldom.TryObjectCreate in line 474 calls CoCreateInstance. That for some reason creates a thread and the thread handle is never freed. However, there isn't really anything you can do about this. So you'll have to simply ignore it.

Both of the remaining leaks are true leaks (I think) but they should really not be shown by madExcept because they don't originate in your code. The leak checker is confused about that because madExcept hooks into thread creation (see "madExcept.HookedCreateThread" in the callstack) and that makes the leak checker believe that the leak is caused by Delphi code. Maybe I should look into fixing that, but it's not easy without being able to reproduce this. Do you have a way to reproduce one of these 2 remaining leaks in a simple test project? Maybe already calling CoCreateInstance is enough to reproduce one of the leaks?
rossmcm wrote:P.S. I should mention that there is feature of MadExcept that has an advantage over FastMM's leak reporting: When FastMM generates the leak report, it does so by calling the routine from your application's program, whereas MadExcept seems to do it by spawning a separate viewer task. This means that the application EXE is released back to the IDE straight away and you can accumulate more than one viewer and leave them displayed while you recompile.
The leak report itself is still created by the application EXE. However, the final report is then passed on to the viewer, which is a separate EXE. Yes, that is a nice advantage over FastMM's leak reporting. But it's not the only one. There are several more, let me list them, because I'm proud of my leak reporting solution:

(1) The viewer GUI is of course much nicer than the simple FastMM reporting.
(2) You can double click callstack items in the viewer to make the Delphi editor jump to the right line.
(3) You can delete leaks you've fixed and save the remaining leaks to a file.
(4) Most importantly: FastMM4 only checks leaks in its own memory allocation routines. madExcept hooks about 400 win32 APIs to show you all kinds of other leaks FastMM4 has no idea of. E.g. check the "LeakTest" demo in the "Demos" folder and try which of those leaks FastMM4 detects.

8)
gambit47
Posts: 4
Joined: Wed May 31, 2006 8:02 pm

Re: RegisterExpectedMemoryLeak

Post by gambit47 »

rossmcm wrote:For example, I know that Indy leaks a TIdThreadSafeInteger and 2 of TIdCriticalSection each time my app runs, but this is known about and inconsequential - so I have this at the start of my main program:

Code: Select all

RegisterExpectedMemoryLeak (TIdThreadSafeInteger, 1) ;      
RegisterExpectedMemoryLeak (TIdCriticalSection, 2) ;
For what it is worth, Indy already registers those leaks, you do not need to do it manually. Indy has its own IdGlobal.IndyRegisterExpectedMemoryLeak() function that the affected units call at initialization. Internally, it calls Delphi's System.RegisterExpectedMemoryLeak() (D2006+) unless USE_FASTMM4 is defined, in which case it calls FastMM.RegisterExpectedMemoryLeak() directly. So as long as MadExcept is registering itself as Delphi's default memory manager and providing a callback for System.RegisterExpectedMemoryLeak() to call MadExcept.HideLeak() then Indy's leaks should already be getting registered automatically. I'm not against adding a new USE_MADEXCEPT define to Indy so it can call MadExcept.HideLeak() directly if needed, though.
madshi
Site Admin
Posts: 10365
Joined: Sun Mar 21, 2004 5:25 pm

Re: RegisterExpectedMemoryLeak

Post by madshi »

madExcept's leak checking should automatically handle leaks registered via RegisterExpectedMemoryLeak() correctly. At least that's the theory...
Post Reply