Strange warning: Object 0x10a913ff0 of class NSConcreteMapTable autoreleased with no pool in place

I get the warning once. It seems to have no effect - though it'd be hard for me to notice if I really liked one object.

I can't just ignore this because this is a console app - but for the life of me I can't see why this would happen, now I've read about auto release pools (a really poorly-thought-out idea, IMHO, but I digress).

I tried it with, er, a recent version - 2.1.7?  Something like that (should have written it down)?  I updated to 3.0.0 and the problem persists. 

I am, of course, taking a MessageManagerLock before doing this.  Contemplating simply running it on the MessageManagerThread but would like to figure this out.  But I'll try that anyway and let you know.

I am in fact calling this function repeatedly, but it gives the same warning whether I call it with period 1000ms or 5m.

 

This is the warning:

objc[61498]: Object 0x103b3a940 of class NSConcreteMapTable autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug

and when I set a breakpoint, I get:

 


#0  0x00007fff8c319a0d in objc_autoreleaseNoPool ()
#1  0x00007fff8c305402 in (anonymous namespace)::AutoreleasePoolPage::autoreleaseSlow ()
#2  0x00007fff8c319bec in _objc_rootAutorelease2 ()
#3  0x00007fff8951aa07 in -[NSWindow _setWindowContextForCurrentThread:] ()
#4  0x00007fff88f49677 in -[NSWindow _threadContext] ()
#5  0x00007fff88f0dde7 in -[NSWindow _postingDisabled] ()
#6  0x00007fff88f0d97b in -[NSWindow _postWindowNeedsDisplayOrLayoutOrUpdateConstraintsUnlessPostingDisabled] ()
#7  0x00007fff88f0d566 in -[NSWindow _setNeedsDisplayInRect:] ()
#8  0x00007fff88f0c8ca in -[NSView setNeedsDisplayInRect:] ()
#9  0x00000001019dfa35 in juce::NSViewComponentPeer::repaint () at juce_mac_NSViewComponentPeer.mm:1174
#10 0x00000001018b2947 in juce::Component::internalRepaintUnchecked (this=0x10aa08530, area=@0x10c851110, isEntireComponent=false) at juce_Component.cpp:1904
#11 0x00000001018b2bb6 in juce::Component::internalRepaint (this=0x10aa08530, area=@0x10c8511b0) at juce_Component.cpp:1879
#12 0x00000001018b2a55 in juce::Component::internalRepaintUnchecked (this=0x104841940, area=@0x10c851270, isEntireComponent=false) at juce_Component.cpp:1910
#13 0x00000001018b2bb6 in juce::Component::internalRepaint (this=0x104841940, area=@0x10c851310) at juce_Component.cpp:1879
#14 0x00000001018b2a55 in juce::Component::internalRepaintUnchecked (this=0x1042899a0, area=@0x10c8513c8, isEntireComponent=true) at juce_Component.cpp:1910
#15 0x00000001018ad4c6 in juce::Component::repaint (this=0x1042899a0) at juce_Component.cpp:1855
#16 0x00000001015aaa7c in echomesh::InstrumentComponent::setColor (this=0x1042899a0, c=@0x10c851498) at /development/echomesh/code/cpp/Builds/MacOSX/../../echomesh/component/InstrumentComponent.cpp:29
#17 0x00000001015ac95e in echomesh::InstrumentGrid::setLights (this=0x104841940, lights=0x10aa14a40 "") at /development/echomesh/code/cpp/Builds/MacOSX/../../echomesh/component/InstrumentGrid.cpp:153
#18 0x0000000101592535 in __pyx_pf_9cechomesh_16PyLightingWindow_6set_lights (__pyx_v_self=0x1002b0ee8, __pyx_v_lights=0x108ea7ea0) at cechomesh.cpp:2480
#19 0x0000000101592340 in __pyx_pw_9cechomesh_16PyLightingWindow_7set_lights (__pyx_v_self=0x1002b0ee8, __pyx_v_lights=0x108ea7ea0) at cechomesh.cpp:2450
#20 0x00000001000c4a2c in PyEval_EvalFrameEx ()
#21 0x00000001000c58c9 in PyEval_EvalCodeEx ()
#22 0x00000001000c31bd in PyEval_EvalFrameEx ()
#23 0x00000001000c58c9 in PyEval_EvalCodeEx ()
#24 0x00000001000c31bd in PyEval_EvalFrameEx ()
#25 0x00000001000c58c9 in PyEval_EvalCodeEx ()
#26 0x00000001000c31bd in PyEval_EvalFrameEx ()
#27 0x00000001000c58c9 in PyEval_EvalCodeEx ()
#28 0x000000010003e510 in function_call ()
#29 0x000000010000c932 in PyObject_Call ()
#30 0x00000001000be63d in PyEval_EvalFrameEx ()
#31 0x00000001000c3fed in PyEval_EvalFrameEx ()
#32 0x00000001000c3fed in PyEval_EvalFrameEx ()
#33 0x00000001000c58c9 in PyEval_EvalCodeEx ()
#34 0x000000010003e510 in function_call ()
#35 0x000000010000c932 in PyObject_Call ()
#36 0x000000010001f04b in instancemethod_call ()
#37 0x000000010000c932 in PyObject_Call ()
#38 0x00000001000bc0c7 in PyEval_CallObjectWithKeywords ()
#39 0x0000000100103817 in t_bootstrap ()
#40 0x00007fff936df772 in _pthread_start ()
#41 0x00007fff936cc1a1 in thread_start ()
 

Update: calling the function on the message thread *does* make the warning go away.  But what's going on?

It basically means that you've called some obj-C without having an autorelease pool on the stack. On the message thread, each callback is wrapped in a pool automatically, but if you use a bare thread, you'd need to create one yourself.

I use the JUCE_AUTORELEASEPOOL macro and ScopedAutoReleasePool class for handling this kind of thing - you might need to use something similar.

Arg, this is what reading the documentation had implied to me me - but I'm not actually calling any Objective C (or any Mac-specific routines)!  Except for the Python part, everything I'm doing is pure JUCE, and JUCE seems to handle all its Objective C code correctly.

This is a cross-platform application - if I'm calling something that's Mac specific, I have to get rid of it.

BUT this was extremely helpful corroboration.  

My new theory is that something in the Python interface libraries does this (bad move!), and my attention is focusing on PyByteArray_AsString as its called in the offending thread.  Seems impossible - this is defined in a C++ .h header file - but it seems the only possible candidate.

Breaking...!

Surely your stack trace shows exactly where it's happening - echomesh::InstrumentComponent::setColor calls repaint(), which has to make system calls that expect there to be a pool in place (?)

I could create a pool inside repaint() itself before calling the obj-C windowing methods, but I'd rather not because that'd add quite a lot of overhead to an often-used call, and it's not normally needed if called from threads that are objective-C-friendly..

Oh, no, I had no idea. I thought Juce kept track of all of this for me, so I just didn't look at the Juce code at all!  And now I'm wondering why I never saw this issue in my bigger application??

But now I'm getting it.  Juce threads are Objective-C friendly so anything I do from a Juce thread won't suffer from this issue.  This is the first time I've ever called Juce from a non-Juce thread - thus the issue.

So what's the best cross-platform way to do this, then?  Will I get a corresponding problem in other, non-OS/X operating systems?

Answering myself:  I wrap the two repaints in JUCE_AUTORELEASEPOOL blocks.  How expensive is this?  I'll be doing it an awful lot...

 

Answering myself:  I wrap the two repaints in JUCE_AUTORELEASEPOOL blocks.  How expensive is this?  I'll be doing it an awful lot...

I don't think it's particularly expensive, but it's probably not good to do it more than necessary. Normally you'd wrap each message-thread event invocation in a pool, but I guess it depends how your thread works.