Linear growth of memory usage by the JUCE Demo


#1

The Debug Navigator (the mini profiler) of Xcode 7.1 shows a linear growth of memory usage of the JUCE Demo. This appears to be new.

Without touching the Demo, i.e. staying on the Welcome tab, the memory usage raises from 20.4MB to 48.8MB within 3 minutes.

Since I'm not a profiling-ninja I report this here.
The Apple Instruments leak analyser doesn't detect any leaks.

This is the most I could extract from the Instruments (All Heap & Anonymous VM -> Call Trees):

Bytes Used    Count        Symbol Name
   6.91 MB      99.5%    1753         start
   6.91 MB      99.5%    1753          main
   6.91 MB      99.5%    1753           juce::JUCEApplicationBase::main(int, char const**)
   6.91 MB      99.5%    1753            juce::JUCEApplicationBase::main()
   6.91 MB      99.5%    1753             juce::MessageManager::runDispatchLoop()
   6.91 MB      99.5%    1753              -[NSApplication run]
   6.91 MB      99.5%    1753               -[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:]
   6.91 MB      99.5%    1752                _DPSNextEvent
   6.91 MB      99.5%    1752                 _BlockUntilNextEventMatchingListInModeWithFilter
   6.91 MB      99.5%    1752                  ReceiveNextEventCommon
   6.91 MB      99.5%    1752                   RunCurrentEventLoopInMode
   6.91 MB      99.5%    1752                    CFRunLoopRunSpecific
   6.91 MB      99.5%    1732                     __CFRunLoopDoObservers
   6.91 MB      99.5%    1732                      __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
   6.91 MB      99.5%    1732                       CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*)
   6.91 MB      99.5%    1732                        CA::Transaction::commit()
   6.91 MB      99.5%    1732                         CA::Context::commit_transaction(CA::Transaction*)
   6.76 MB      97.4%    148                          _dispatch_async_f_slow
   6.75 MB      97.3%    13                           _dispatch_introspection_queue_item_enqueue_hook
   6.75 MB      97.3%    13                            gcd_queue_item_enqueue_hook
   6.75 MB      97.3%    13                             get_entry_from_free_list
   6.75 MB      97.3%    13                              mach_vm_allocate
   8.44 KB       0.1%    135                           _dispatch_continuation_alloc_from_heap
 125.11 KB       1.7%    1531                          CA::Transaction::run_commit_handlers(CATransactionPhase)
  21.05 KB       0.2%    41                          CA::Layer::layout_and_display_if_needed(CA::Transaction*)
   4.91 KB       0.0%    12                          CA::Layer::commit_if_needed(CA::Transaction*, void (*)(CA::Layer*, unsigned int, unsigned int, void*), void*)
   1.69 KB       0.0%    19                     __CFRunLoopRun
     16 Bytes    0.0%    1                     malloc_zone_malloc
    160 Bytes    0.0%    1                +[NSObject allocWithZone:]
  28.78 KB       0.4%    20         start_wqthread
   1.12 KB       0.0%    9         thread_start

Ok, memory allocation in the juce::MessageManager::runDispatchLoop()...

Specs:
JUCE commit 4b4d216, October 28 2015,
OS X 10.11.1, Xcode 7.1

Worth mentioning: This doesn't happen when profiling in VisualStudio 2013 under Windows 8.

Might be an issue introduced by Apple with Xcode 7.1.
Or is it caused by some ground work for the upcoming Projucer?

 

Cheers,

Samuel


#2

Nope.. it sits at a steady 25MB when I run it here.

But I wouldn't see it as a problem unless it keeps rising indefinitely. 48MB is a very small amount of memory these days, and could easily just be the heap/OS optimising itself, or some heap fragmentation.


#3

Offtopic, i used a cpp memory pool class, similar to this http://unbui.lt/#!/post/cpp-memory-pools (Had to make the stack threadsafe), and could significant improve performance, especially for creating objects in the Audio-Thread this is intersting. Maybe its worth a try to use something similar for the messaging system.

 


#4

Good to know that it is fine on your system.

Thank you for your explanations!

I wouldn't see it as a problem unless it keeps rising indefinitely.

I'm afraid that might be the case. The increase seems quite uniform. Maybe it will settle at one point though.

 0m:  20.4 MB
 1m:  30.2 MB
 2m:  40.2 MB
 3m:  50.0 MB
 4m:  61.5 MB
 5m:  70.3 MB
 6m:  79.7 MB
 7m:  90.3 MB
 8m: 100.0 MB
 9m: 107.0 MB
10m: 113.7 MB
11m: 119.9 MB
12m: 129.8 MB
13m: 140.2 MB
14m: 147.0 MB
15m: 157.3 MB

Maybe another JUCE user might take a look at the memory usage on his/her machine...

 

Btw. I had to completely wipe and reinstall my Mac 3 week ago because of a hardware failure. It is a fresh install of OS X 10.11 and Xcode 7.


#5

Seems to be okay here too, but running on Yosemity. Tried both Debug Profiler, and running Profile Scheme on Instruments


#6

I'm on 10.10. I guess there could be something different in the memory management on 10.11, but there's no actual leak in the C++ code so not really sure what's different here.


#7

Thank you chkn and jules for your replies! This might be an Xcode on El Capitan issue.
Xcode and Instruments did show similar results for the Debug as well as for the Release Build (results as posted above).

When compiled for Release, regularly run (not from within Xcode) and monitored with 'Activity Monitor', it looks alright:

 0m:  18.8 MB
 1m:  21.2 MB
 2m:  21.4 MB
 3m:  21.7 MB
 4m:  21.8 MB
 5m:  21.8 MB
 6m:  22.6 MB
 7m:  22.6 MB
 8m:  22.6 MB
 9m:  22.6 MB
10m:  22.6 MB
11m:  22.6 MB
12m:  22.6 MB
13m:  22.6 MB
14m:  23.1 MB
15m:  23.1 MB

So well, don't think this is something to be concerned about.

 

@chkn: Thank you for the link http://unbui.lt/#!/post/cpp-memory-pools . Very informative!


#8

The threadsafety of that memory pool article worried me too! I guess the performance of the threadsafe version isn't as good as the author claims for the unsafe one..

I assume you used a lock-free stack rather than CriticalSections?


#9

i used CriticalSections but it was still much faster than a real allocation. I tried to make a lock-free  pointer-stack, but I didn't finished. (BTW does anybody now how expensive a non blocking CriticalSection is?, it is comparable to a atomic SetAndCompare/Spinlock )

BTW i don't like the SpinLock from JUCE, i calls  Thread::yield(); (When you using SpinLock (almost in Time-Critical-Situations) you want it to be as fast as possible, not wanting to  call any OS-callback, so i think the name SpinLock is misleading here  )

 

void SpinLock::enter() const noexcept

{

    if (! tryEnter())

    {

        for (int i = 20; --i >= 0;)

            if (tryEnter())

                return;

 

        while (! tryEnter())

            Thread::yield();  <---- eh?

    }

}