New leaks detected in the tip (MessageManager)?


#1

I just updated to the tip to fix (hopefully) the DrawableButton issue, and now I’m getting some new leaks I haven’t seen before and believe do not belong to me - it looks as if the MessageManager is leaking…?

*** Leaked objects detected: 1 instance(s) of class N4juce9HeapBlockIPNS_7MessageEEE
JUCE Assertion failure in …/…/…/…/…/rec/src/…/…/juce/juce_amalgamated.h, line 3296
Debugger() was called!
(gdb) continue
*** Leaked objects detected: 1 instance(s) of class N4juce14MessageManagerE
JUCE Assertion failure in …/…/…/…/…/rec/src/…/…/juce/juce_amalgamated.h, line 3296
Debugger() was called!
(gdb) continue
*** Leaked objects detected: 1 instance(s) of class N4juce9HeapBlockIPKNS_15MessageListenerEEE
JUCE Assertion failure in …/…/…/…/…/rec/src/…/…/juce/juce_amalgamated.h, line 3296
Debugger() was called!

EDIT: I put delete MessageManager::getInstance() in my shutdown code and now I get an assertion failure indicating that I’m leaking some sort of MessageListener object.

Perhaps I am leaking this MessageListener object and it’s keeping the MessageManager from being deleted, and that’s why I’m getting this slightly misleading error?


#2

(I just this second checked in a fix for the drawablebutton thing, so you probably want to try again…)

It sounds like you might just be calling MessageManager::getInstance() after it has already been shut down, so that the new instance you create will be leaked?


#3

Interesting thought! I’ll set a breakpoint.

I should add that this didn’t happen before I upgraded to the tip - I wasn’t very far behind, either - but I still feel it’s symptomatic of some issue in my code. The leak detector has gone off several times as you introduced more parts but each time it was some deficiency on my part (which included variables deliberately leaked with static Foo *instance = new Foo()).


#4

Boy, I wish XCode were more reliable with its garbage-y debugger.

Setting breakpoints, I am almost certainly not requesting MessageManager::instance() during shutdown… it seems as if the MessageManager is simply not being deleted at all, and that there is still a single MessageListener on it (which also puzzles me - by my count it should be two).

There’s one created here:

#0 0x001cfec7 in juce::MessageListener::MessageListener at juce_amalgamated.cpp:38772
#1 0x004b1168 in juce::InternalTimerThread::InternalTimerThread at juce_amalgamated.cpp:39203
#2 0x004b12ca in juce::InternalTimerThread::add at juce_amalgamated.cpp:39332

one here:

#0 0x001cfec7 in juce::MessageListener::MessageListener at juce_amalgamated.cpp:38772
#1 0x001cff2a in juce::ActionBroadcaster::CallbackReceiver::CallbackReceiver at juce_amalgamated.cpp:38114
#2 0x002c071e in juce::ActionBroadcaster::ActionBroadcaster at juce_amalgamated.cpp:38125
#3 0x002c084e in juce::MessageManager::registerBroadcastListener at juce_amalgamated.cpp:38941
#4 0x00369d77 in juce::JUCEApplication::initialiseApp at juce_amalgamated.cpp:18803

and that seems to be it.

When I start to quit, I never touch any MessageManager methods at all and MessageManager::instance has not been cleared - and I never seem to hit either of the MessageListener destructors either, I didn’t trust XCode so I put print statements there.

Let me upgrade to the new tip and see if this goes away again! Hang loose… nope, still the same behaviour (though it fixes the DrawableButton issue, thanks!)

Let me ask two questions…

  1. How does the main MessageQueue get deleted?
  2. How do those two instances of MessageListener that Juce creates get deleted?

One more update: apparently, setting #define JUCE_CHECK_MEMORY_LEAKS 0 causes a host of linking errors in XCode looking like:

“non-virtual thunk to juce::label::textEditorEscapeKeyPressed(juce::TextEditor&)”, referenced from:
vtable for rec::widget::status::time::TextComponentin MainPage.o
vtable for rec::widget::status::time::TextComponentin RecWindow.o
vtable for rec::widget::status::time::TextComponentin Time.o"

setting #define JUCE_CHECK_MEMORY_LEAKS 1 gets everything back to normal again.

This is in my unoptimized debug build.


#5

Now I understand the issue.

The issue is a static destructor going off very late in the process, bringing everything back to life. (You might consider an assert preventing code from creating the message manager queue again while in the shutdown process.)

I have a set of drawables that are created on demand and live for the duration of the program. Before the leak detector, I just let them drop on the floor deliberately. I very recently added the static destructor but some change in the order of deletion in the new tip changed the destructor order. I knew the static destructor was an issue but it worked and there doesn’t seem to be a way to say, “Don’t consider these items for leak detection.”

Not too hard to fix though, I’ll just keep a list of them somewhere and kill 'em at the end. However, the issue in turning the leak manager off remains…


#6

Aha, yes, the leak detector will have problems if you use it for statically-created objects, because it’s at the mercy of the order in which the runtime chooses to destroy them. For objects like components that may try to do complicated stuff in their destructors it’s definitely a much better idea to put them in a singleton and use DeletedAtShutdown or something to get rid of them early in the shutdown process.