I have a method which needs to run in its own thread 88 times per second (it's a callback for an audio unit.) Should I avoid creating an NSAutoreleasePool each time it's called?
If you can avoid it, do that. If you can’t, there’s no need to worry about it, autorelease pools are created and released quite quickly. If you need a precise answer, set up a simple test and measure (which is always a good idea when speaking about performance).
Creating the NSAutoReleasePool itself shouldn't be too slow, but if there are a lot of objects to be dealloc'ed when you 'drain' the pool, that could start get slow. It's probably worth profiling how long the pool drains are taking.
Please see Mike Ash's Performance Comparisons of Common Operations. When he tested in 10.5, creating and destroying an autorelease pool took 0.0003577 milliseconds.
Assuming that you've just come back from Instruments or Shark with concrete evidence that autorelease pools really are a performance concern in your app…
Creating your own autorelease pools is an answer to a dilemma. You do it when you are creating a lot of objects, in order to not create too many at once and either enter paging hell (on the Mac) or get a memory warning and/or termination (iPhone OS).
But autorelease pools are objects, too. They aren't free. The expense of a single autorelease pool is tiny, but in a loop where you're creating lots of objects, you're probably creating one pool every X objects, draining it, and creating another one for the next X objects.
Even then, the autorelease pools probably aren't that many and so won't add up to much. You should see this in your Instruments or Shark profile: Most of the time spent in -[NSAutoreleasePool drain]
is, in turn, spent in -[NSObject release]
. That's time you'll be spending whether you use an autorelease pool or not.
So the real solution in such cases is simply to create fewer objects. This can mean:
- Using and reusing buffers whenever possible, reallocating a previously-used buffer when the size needed changes. You may want to use the
malloc_good_size
function to round up the size, to make it less likely that you'll need to reallocate (you can skip reallocating if the old needed size and new needed size both round up to the same number). You may also consider only growing the buffer, never shrinking it. - Using and reusing mutable objects. For example, if you build up a string and then write it out to a document, instead of releasing it and creating a new one, delete its entire contents, or replace the entire old contents with the first portion of the “new” string.
- Adjusting the value of X (your pool-disposal threshold). Higher X means more momentary memory consumption, but fewer pools created and thrown away. Lower X means more pools, but less risk of paging out or getting a memory warning. This is unlikely to make much of a difference except when you lower X too far, or raise it from being too low.