Component unit testing causes memory leaks

I have some Catch2 unit tests for GUI components (derived from the juce::Component) in my project, like so:
{
MessageManager::getInstance(); // Force the MessageManager singleton to create an instance
MessageManagerLock mmLock(Thread::getCurrentThread());

         MyGuiComponent componentUnderTest();

        // Test the component ...

        MessageManager::deleteInstance();

}

The tests execute just fine but for some reason the juce::Component base class causes a number of memory leaks when componentUnderTest goes out of scope:

*** Leaked objects detected: 1 instance(s) of class LookAndFeel_V4
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 1 instance(s) of class Image
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 1 instance(s) of class LookAndFeel_V2
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 1 instance(s) of class LookAndFeel
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 1 instance(s) of class DisplaySettingsChangeCallback
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 1 instance(s) of class Desktop
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 1 instance(s) of class ComponentAnimator
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 1 instance(s) of class OwnedArray
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 1 instance(s) of class MouseInputSource
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 1 instance(s) of class MouseInputSourceInternal
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 1 instance(s) of class OwnedArray
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 1 instance(s) of class TypefaceCache
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 3 instance(s) of class AsyncUpdater
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 2 instance(s) of class WaitableEvent
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
*** Leaked objects detected: 1 instance(s) of class MessageManager
JUCE Assertion failure in juce_LeakedObjectDetector.h:92
JUCE Assertion failure in juce_Singleton.h:50
JUCE Assertion failure in juce_Singleton.h:50

I wonder why Components don’t clean up after themselves? Perhaps they somehow share these objects with other Components behind the scenes? I have tried looking at the source code but it’s not really obvious to me what’s going on…

Finally (and most importantly), I wonder how I can avoid these memory leaks in my unit tests?

You created an instance of the MessageManager but didn’t delete it.

Call MessageManager::deleteInstance() before your program closes.

I’m afraid that’s not it. Deleting the MemoryManager instance makes no difference.

I have added MessageManager::deleteInstance(); to the example for clarity.

At second glance, deleting the memory manager actually does make a difference… these lines no longer appear in the output when I call MemoryManager::deleteInstance() :

*** Leaked objects detected: 1 instance(s) of class MessageManager
JUCE Assertion failure in juce_LeakedObjectDetector.h:92

The other memory leaks remain though.

I don’t think you want to be manually creating the MessageManager like that.

You should probably make a class that inherits from JUCEApplicationBase so it can handle the initialisation and shutting down properly.

OK, I solved it. Thanks to @ImJimmi for pointing me in the right direction.

Looking at the source for JuceApplicationBase, I noticed the following 2 lines of code in the shutdown method:

DeletedAtShutdown::deleteAll();
MessageManager::deleteInstance();

Adding these lines to my unit test solves the problem, i.e.:

{
    MessageManager::getInstance(); // Force the MessageManager singleton to create an instance
    MessageManagerLock mmLock(Thread::getCurrentThread());

    MyGuiComponent componentUnderTest();

    // Test the component ...

    DeletedAtShutdown::deleteAll();
    MessageManager::deleteInstance();
}

Another way to achieve this might be to create a class that derives from JuceApplicationBase, as @ImJimmi suggested.

1 Like

There is a better way, which is to put an instance of ScopedJuceInitialiser_GUI on the stack at the beginning of your test program.
This will create the MessageManager and what’s all necessary and when it goes out of scope, it will do the necessary cleanup. The classes affected inherit DeletedAtShutdown, if you wonder how it works.

2 Likes

@daniel nice, I’ll use that.