
Alternative Objective-C object allocation for large arrays - jawngee
http://cocoawithlove.com/2010/08/alternative-objective-c-object.html
======
malkia
If you work on a video game, you almost always have to do something like that.
In fact you never rely on malloc/new/delete/free for a big portion of the
code. And it's usually 3rd party libraries, or the sdk itself that goes and
uses malloc/free (new/delete) directly.

Basically we do a statistic, and keep it over time - for a given level what
object sizes there are, and what's their count, then we preallocate arrays
with these sizes, or allocate them in big chunks (or instead of even
allocating them, just increase a pointer a to buffer with the size).

Another example would be a CGI. Instead of having malloc/free just have one
big block and just increase a pointer and pretend to be just allocating, no
free. Then just exit the application, and obviously whatever memory was used
is gone. (This is for short running CGI scripts).

~~~
illumen
Indeed - for realtime allocation at runtime is a no no.

I like your technique of using statistics to guide your allocations. Another
form of profile guided optimisation :) I guess this could be applied generally
to programs which used a similar amount of memory every time.

Many well designed libraries let you supply a malloc/free/realloc/calloc/etc.
You can also patch system ones in other ways... but it's best to be explicit I
think. When you start using multiple malloc/free implementations, you have to
be very careful you use the correct malloc/free on each bit of memory.

Other common techniques are memory pools, and using mmap.

mmap allows multiple processes to possibly use the same memory(and file system
cache! woot). You can get realtime behaviour on most OSen if you're careful
too. You can even get some video cards to use the mmap'd area of memory! (many
apple cards have an opengl extention that allows you to do this for textures
etc). That can be a 1/3rd memory saving because you can use less file system
cache, and video memory. The best saving though, is less copying between the
different subsystems.

Memory pools let you do another tricky optimisation... your init method does
not need to do all the work each time. Since it's possible to move your object
into a sane state doing less work. Like the article mentions, you can
initialise all of your objects at once too (it's always faster to do things in
batches).

Many systems use memory pools (including python, heaps of game engines etc).
You can even make it transparent to the programmer - so they get the
advantages without having to do extra work.

Some people who do game programming in C allocate everything statically - and
don't do any malloc/free at all. I've seen them write very nice, and clean
code that works perfectly fine using this technique.

I think memory techniques are where you can gain the most performance these
days :)

------
Zev
I was talking to someone about this article on IRC a few days ago. He
mentioned that Apple has something similar to this, NSZone (which has been
around since 10.0 (likely NeXT)). However, NSZone's usage isn't really
recommended anymore (if ever). Nor is it very documented -- just function and
parameter names, not usage patterns[1].

1\. Search for NSZone on
[http://developer.apple.com/mac/library/documentation/Cocoa/R...](http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html)

~~~
malkia
Could it be because of the garbage collecting? I'm not sure whether it's that
related

~~~
Zev
Garbage collection likely has something to do with NSZone's (perceived on my
part) deprecation. My understanding (although I can't find it documented) is
that NSZone doesn't have any effect on allocations handled by the GC. This is
also the default (found-documented) behavior for CFAllocator (although this
can be changed, which might be why CFAllocator is better documented).

Also, NSZone is an opaque C structure -- you don't get to see its fields
without getting your hands (slightly) dirty. It's defined as:

    
    
      typedef struct _NSZone NSZone;
    

Random thought: If you have a lot of objects that can take advantage of toll-
free bridging, I wonder how well it would work to use your own CFAllocator
that doesn't use the GC in a GC'd environment.

~~~
jonhendry
I'm pretty sure NSZone was unofficially deprecated well before Objective-C
added garbage collection.

Essentially, they were a good idea in theory, but not in practice. For one
thing the Cocoa frameworks wouldn't play along with your carefully considered
zone strategy. Then you get objects in zones with pointers to non-zoned
objects and vice versa.

~~~
Zev
I think we might be thinking about the same time period, 4 or 5 years ago.

CoreFoundation had something vaguely resembling garbage collection introduced
in 10.4, with CFMakeCollectable[1]. I've always thought of that time period as
being when NSZone was more or less deprecated. There were a lot of other big
(and small) design changes that were in that era as well; bindings were
introduced, calendars changed, etc.

1\.
[http://developer.apple.com/mac/library/documentation/CoreFou...](http://developer.apple.com/mac/library/documentation/CoreFoundation/Reference/CFTypeRef/Reference/reference.html#//apple_ref/c/func/CFMakeCollectable)

~~~
chc
That wasn't "something vaguely resembling garbage collection" — it was a no-op
until garbage collection was finally introduced half a decade later.

And NSZone was already out of favor when I started programming Cocoa, on OS X
10.1. It just didn't have any advantages under OS X's memory model. It
certainly wasn't a preallocated object pool like this. As it was explained to
me at the time, the main point of NSZone originally was that it let you to
blow away the whole zone at once without needing to release every single
object. This was no longer the case in 10.1 (and I don't think it was even the
case in 10.0).

~~~
pohl
NSZone was born when memory was small and paging to disk was expensive &
frequent. Zones were to help you group objects that would likely be used
together onto the same virtual memory page so you could decrease the
likelihood of thrashing.

