[racket] debugging memory allocation

From: Jay McCarthy (jay.mccarthy at gmail.com)
Date: Fri Nov 7 21:45:21 EST 2014

Robby's advice of using backtrace can be useful. But it is pretty
complicated to use, especially with an interactive application. If you
go that route, you want to make an automated version of your code.
Another strategy is to put your model and your view in different
threads, give them different custodians, and monitor (via sampling)
their memory.

A general strategy is to minimize allocation per-frame, use contiguous
memory when you can, and reuse IT when you can. It is easy to start
writing C code if you go down this path and it may not help.

At a glance of your code...
- draw-view seems VERY expensive manipulating all those lists. It may
be better to actually iterate through the space objects 4 times
filtering inside of the for loop. Your algorithm will run in 4*N time
but it will use constant memory, as opposed to what you have now which
runs in 3*N (filter twice and then remove over objects) + N
(filter/remove over effects, which could be the entire size of
objects) + N (append over 3 lists ending in effects, where the three
lists are all the objects) = 5*N. Thus you are likely to be faster in
time AND in memory.
- draw-overlay does a VERY memory expensive operation on the messages.
filter allocates N conses, then you reverse (N conses), then take 8.
It would be way faster to allocate a size 8 ring buffer and insert
each message into it then read them out in order. This would have
constant memory and only a single pass over the data.
- In many places in your model, I see an inefficient use of snoc as
(cons l (list x)). If you are snoc-ing, you should use a real queue.
If it needs to be functional, look at pfds. Every time you do that,
you are reallocating all N cons cells. That means that reduce-ship! is
doing it in a loop. This means you are using n^k memory where k is the
number of iterations. At the very least, put them on to changes as
cons and the reverse once at the end.
- update-energy! makes a similar mistake of using lists rather than a
priority queue for the suckers

My guess is that you are trying to find a magic bullet but there are
just a few little algorithmic choices that will make a huge difference
in your code.


On Thu, Nov 6, 2014 at 10:39 PM, David Vanderson
<david.vanderson at gmail.com> wrote:
> I'm having a UI problem in my game where major GCs cause noticeable,
> frequent pauses (every 5-15 seconds).  Jay's advice was to control
> allocation.  Minor GCs are no problem, and I'm okay with infrequent major
> GCs.
> Problem is I don't know how to go about tracking this down, and need advice.
> So far, all I know to do is run tests like this:
> $ racket -W debug test-refresh.rkt 2>&1 | grep "^GC"
> ...wait until I see a stable pattern:
> GC: 0:MAJ @ 137,893K(+-15,317K)[+6,816K]; free 76,189K(-76,189K) 142ms @
> 7259
> GC: 0:MAJ @ 94,536K(+28,039K)[+6,816K]; free 32,910K(-49,278K) 156ms @ 11879
> GC: 0:min @ 94,457K(+44,486K)[+6,816K]; free 23,981K(-23,981K) 12ms @ 16275
> GC: 0:min @ 103,306K(+35,637K)[+6,816K]; free 23,929K(-23,929K) 9ms @ 20731
> GC: 0:min @ 112,144K(+26,799K)[+6,816K]; free 23,949K(-23,949K) 11ms @ 25093
> GC: 0:min @ 121,026K(+17,917K)[+6,816K]; free 24,004K(-24,004K) 12ms @ 29235
> GC: 0:min @ 129,853K(+9,090K)[+6,816K]; free 24,001K(-24,001K) 11ms @ 33361
> GC: 0:min @ 138,683K(+260K)[+6,816K]; free 23,990K(-23,990K) 12ms @ 37540
> GC: 0:min @ 147,524K(+-8,580K)[+6,816K]; free 24,062K(-24,062K) 10ms @ 41429
> GC: 0:MAJ @ 156,293K(+-17,349K)[+6,816K]; free 94,638K(-88,638K) 139ms @
> 45517
> GC: 0:MAJ @ 94,486K(+38,457K)[+6,816K]; free 33,231K(-14,911K) 164ms @ 50118
> I couldn't find info in the docs about how to interpret these numbers (did I
> miss it?).  I'm taking the first number as a memory growth, and the last
> number as milliseconds, so between major GCs in this run, I'm generating
> about (147,524K - 94,457K) / (41429ms - 16275ms) = 2.1 K / ms or about 2.1 M
> / s.
> How should I go about figuring out how much garbage I'm generating? Is there
> a way to trace where it's coming from?
> Thanks,
> Dave
> ____________________
>  Racket Users list:
>  http://lists.racket-lang.org/users

Jay McCarthy

           "Wherefore, be not weary in well-doing,
      for ye are laying the foundation of a great work.
And out of small things proceedeth that which is great."
                          - D&C 64:33

Posted on the users mailing list.