Hacker News new | past | comments | ask | show | jobs | submit login
Alternative Objective-C object allocation for large arrays (cocoawithlove.com)
42 points by jawngee on Sept 5, 2010 | hide | past | favorite | 10 comments



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).


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 :)


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...


There is a bit of back and forth about them on CocoaDev:

http://www.cocoadev.com/index.pl?NSZone


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


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.


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.


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...


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).


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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: