+3  A: 

There's nothing wrong with using autorelease, but when you allocate objects in a loop, you should always call release explicitly.

Using autorelease:

for (int i=0;i<1000;i++) {
    NSString *s = [[[NSString alloc] init] autorelease];
}

// at this point, there are 1,000 unreleased string objects in memory

Using release:

for (int i=0;i<1000;i++) {
    NSString *s = [[NSString alloc] init];

    [s release];
}

// at this point, no string objects are "alive"

As you can see, you have to be really careful when using autorelease in loops.

Philippe Leybaert
I like that "exception" to the rule. What if you "pushed down" the `alloc init` and the `autorelease` to a method called in your loop?
Yar
Same thing. If there is a chance that your code will be called in a loop, you should always use release instead of autorelease.
Philippe Leybaert
Perfect, thanks for that.
Yar
But if you're going to release yourself, you should wrap it in a `@finally` block, right?
Yar
Yes, definitely
Philippe Leybaert
But no one does that ever, I bet ;)
Yar
True, but Objective-C depends less on exception handling than, say, Java or C#. If an exception is thrown in an ObjC app, it's usually caused by a bug in your app.
Philippe Leybaert
okay, interesting, thanks
Yar
+2  A: 

You should be aware how autorelease works. Each thread in your application normally has a single autorelease pool. Objects can be registered in the pool. At the time they are registered, the pool determines the stackframe they belong to and will automatically pop the from the pool whenever that stackframe is left.

While this may seem costly (and it certainly is compared to direct retain/release), I don't think it even close to the cost a generation mark and sweep garbage collector can have.

Where autorelease really shines is in all situations where exceptions may be raised and there's no try/catch around. Autorelease is definitely preferable to a direct release in such cases.

There are, however, situations where you should avoid autorelease (the same goes for garabge collected environments where you should try to avoid these situations too). Creating temporary, autoreleased objects in a loop which runs a huge number of times is such a scenario, which puts significant stress on a garbage collector or the autorelease pool.

Replacing release with autorelease should be avoided in worker threads that are very simple and can live without the overhead of an autorelease pool. So the guideline is: Whenever you can avoid it, you should, whenever you're unsure autorelease.

Johannes Rudolph
Thanks for that explanation, I had never thought about the try-catch problem. Shouldn't explicit releases be placed in finally blocks (assuming they exist)?
Yar
yes, of course they should.
Johannes Rudolph
But that would be even sloppier and more error-prone/harder-to-read. Which is why the `autorelease`-always idea is so attractive.
Yar
@yar: It depends, when you're inside a busy loop I would use try/catch, if it's just a one-time operation autorelease is certainly cleaner.
Johannes Rudolph
@yar: There's another aspect to this, early releasing allows you to realloc (=reuse) the same block again. Memory is the bottleneck nowadays compared to cpu power, so you do good in avoiding cache misses as much as possible. If a block has just been released, it is likely it is still in the cache and used for the next allocation (leaving fragemntation etc. aside). Here's an interesting link: http://research.scee.net/files/presentations/gcapaustralia09/Pitfalls_of_Object_Oriented_Programming_GCAP_09.pdf
Johannes Rudolph
Hmmmm... really interesting stuff (though I have to say that I'd rather be doing what *I* consider to be programming)... but this brings me back to my initial question: In a non-trivial non-game app (a mail application, let's say), just how much of a difference does this make? In Java, for instance, concatenating Strings is considered to be costly, but in a web app, it's a total non-issue whether you use StringBuffer or String (see Groovy for some really inefficient code which is tight-enough). Let's reduce the question to things that you do NOT do in large (500+ iteration) loops.
Yar
I believe it doesn't really matter. I wouldn't worry to much about the performance difference of autorelease vs. release until a profiler showed me there's a bottleneck in that loop. Getting things done and having no memory leaks is more important.
Johannes Rudolph