views:

3720

answers:

11

Most of Apples documentation seems to avoid using autoreleased objects especially when creating gui views, but I want to know what the cost of using autoreleased objects is?

UIScrollView *timeline = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 20, 320, 34)];
[self addSubview:timeline];
[timeline release];

Ultimately should I use a strategy where everything is autoreleased and using retain/release should be the exception to the rule for specific cases? Or should I generally be using retain/release with autorelease being the exception for returned objects from convenience methods like [NSString stringWithEtc...] ?

+2  A: 

As I understand it, the main downside to using autorelease is that you don't know when the object will finally be released and destroyed. This could potentially cause your app to use a lot more memory than it needs to if you have a lot of autoreleased objects hanging around but not yet released.

Andy
+13  A: 

There are two costs:

  1. (Assuming you have an option to avoid autoreleased objects.) You effectively unnecessarily extend the lifetime of your objects. This can mean that your memory footprint grows -- unnecessarily. On a constrained platform, this can mean that your application is terminated if it exceeds a limit. Even if you don't exceed a limit, it may cause your system to start swapping, which is very inefficient.

  2. The additional overhead of finding the current autorelease pool, adding the autoreleased object to it, and then releasing the object at the end (an extra method call). This may not be a large overhead, but it can add up.

Best practice on any platform is to try to avoid autorelease if you can.

To answer the questions:

Ultimately should I use a strategy where everything is autoreleased and using retain/release should be the exception to the rule for specific cases?

Quite the opposite.

Or should I generally be using retain/release with autorelease being the exception for returned objects from convenience methods like [NSString stringWithEtc...] ?

You should always use retain/release if you can -- in the case of NSString there is typically no need to use stringWithEtc methods as there are initWithEtc equivalents.

See also this question.

mmalc
Both of your reasons boil down to prematurely optimizing for performance rather than code readability. And they both have a simple solution when it matters: An NSAutoreleasePool.
Steven Fisher
+6  A: 

The costs are:

  1. The time to locate the current thread's autorelease pool and add the object to it.
  2. The memory occupied by the object until it is released at some later point.

If you want to be very conservative with your memory usage, you should avoid autorelease. However, it is a useful technique that can make code more readable. Obsessively using retain/release falls under the umbrella of "premature optimization."

If you are in Cocoa's main event handling thread (which you are most of the time), the autorelease pool is emptied when control returns to the event handler. If your method is short and doesn't loop over large amounts of data, using autorelease to defer deallocation to the end of the run loop is fine.

The time to be wary of autorelease is when you are in a loop. For example, you are iterating over a user's address book and perhaps loading an image file for each entry. If all of those image objects are autoreleased, they will accumulate in memory until you have visited the entire address book. If the address book is large enough, you may run out of memory. If you release the images as soon as you are done with them, within the loop, your app can recycle the memory.

If you can't avoid autoreleasing inside a loop (it's being done by code you didn't write and can't change), you can also manage an NSAutoreleasePool within the loop yourself if needed.

So, be mindful of using autorelease inside loops (or methods that may be called from loops), but don't avoid it when it can make code more readable.

benzado
This is not considered to be "best practice", particularly on resource-constrained platforms. Note also Jim Puls' observation about debugging.
mmalc
What's not "best practice"? I'm saying that for the costs of autorelease (which we agree on) you can improve code readability. Sometimes this is an acceptable trade-off.
benzado
Using autorelease is not best practice.
mmalc
Avoiding autorelease is not best practice.
benzado
Yes, it is. Perhaps I might ask on what authority you make that assertion?
mmalc
My own experience developing shipping software. In the real world sometimes code readability trumps inconsequential optimizations. You are being far too fundamentalist in your assertion that autorelease should be avoided at any cost. Sometimes it is worth the cost.
benzado
My assertion comes from discussion with iPhone engineers whilst writing (and setting policy for) iPhone sample code (and later for WWDC presentations) and subsequent discussion with AppKit engineers to ensure consistency of message. The consistent message was: avoiding autorelease is best practice.
mmalc
You may choose not to follow best practice for memory management for other reasons, but that does not change what is considered best practice for memory management.
mmalc
Best practice for Cocoa memory management is the use of `autorelease`, and it's associated convenience methods, etc. Best practice is to switch to manually managing `retain`/`release` if, ***and only if***, objective data from profiling tools indicates autorelease pool hot spots. Even then, the use of a carefully placed `NSAutoreleasePool` is preferred. Forget what @mmalc is saying- my iPhone/iPod touch has more ram than my first Mac that ran OS X... and no one programmed for those machines any differently than they program for todays machines.
johne
+7  A: 

I'm surprised nobody has mentioned this yet. The biggest reason to avoid autoreleased objects when you can has nothing to do with performance. Yes, all of the performance concerns mentioned here are absolutely valid, but the biggest downside to autorelease is that it makes debugging significantly more difficult.

If you have an overreleased object that's never autoreleased, it's trivially easy to track down. If you have a user-reported crash that happens intermittently with a backtrace somewhere south of NSPopAutoreleasePool, good luck...

Jim Puls
This was a valid reason back in the days of Leopard, when Xcode didn't have the static analyzer integrated yet and Instruments sucked. Now, it's not that hard to drive out existing memory-mishandling bugs using Instruments and prevent the bugs from existing in the first place by turning on and obeying the static analyzer.
Peter Hosey
+1  A: 

Others have answered whether you should autorelease, but when you must autorelease, drain early and drain often: http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html

Graham Lee
+13  A: 

I have to disagree with Jim Puls - I think that not using Autorelease makes debugging more difficult, because you are more likely to find yourself accidentally leaking memory. Of course Clang static analyzer can pick up some of these instances, but for me, the slight overhead costs in habitually using autorelease are far overshadowed by my code being less likely to be buggy.

And then, only if I have a tight loop I need to optimize will I start looking at performance. Otherwise this is all just premature optimization, which is generally considered to be a bad thing.

danwood
But isn't accidentally leaking memory much more desirable than having an untraceable crash? I only speak from experience.
Jim Puls
Jim: I agree with you, this is my experience as well
cschreiner
A: 

One side note to keep in mind is if you are spawning a new thread, you must setup a new Autorelease pool on that thread before you do anything else. Even if you are not using autorelease objects, chances are that something in the Cocoa APIs is.

lfalin
+1  A: 

I notice the code sample you provided is for the iPhone. Apple specifically recommends avoiding autoreleased objects for iPhone apps. I can't find the specific reasoning, but they were hammering this point at WWDC.

David Grant
+6  A: 

One benefit to using autorelease pools is that they are exception safe without using @try/@finally. Greg Parker ('Mr. Objective-C') has a great post explaining the details of this.

I tend to use autorelease a lot as its less code and makes it more readable, IMO. The downside, as others have pointed out, is that you extend the lifetime of objects, thus temporarily using more memory. In practice, I have yet to find overuse of autorelease to be a significant issue in any Mac app I've written. If high memory usage does seem to be an issue (that isn't caused by a genuine leak), I just add in more autorelease pools (after profiling to show me where I need them). But, in general, this is quite rare. As Mike Ash's post shows (Graham Lee linked to it), autorelease pools have very little overhead and are fast. There's almost zero cost to adding more autorelease pools.

Granted, this is all for Mac apps. In iPhone apps, where memory is more tight, you may want to be conservative in your use of autorelease. But as always, write readable code first, and then optimize later, by measuring where the slow/memory intensive parts are.

Dave Dribin
+6  A: 

I generally use autoreleased objects these days because they tend to result in simpler, easier to read code. You declare and initialize them, then let the drop out of scope. Mechanically they exist quite a bit longer, but from the perspective of the person writing the code it is equivalent to a stack declared object in C++ automatically being destructed when the function returns and its frame is destroyed.

While there is an efficiency loss, in most cases it is not significant. The bigger issue is the more extant objects and later memory recovery can lead to a more fragmented address space. If that is an issue it usually is fairly simple to go in and switch to manual retain/release in a few hot methods and improve it.

As others have said, readability trumps performance in nonperformance sensitive code. There are a number of cases where using autoreleased objects leads to more memory fragmentation, but in any case where the object will outlive the pool it will not. In those cases the only price you are paying is finding the cost of finding the correct autorelease pool.

Louis Gerbarg
A: 

Old thread, but chipping on for the benefit of newer readers.

I use autorelease vs retain/release depending on the risk of autorelease bugs specific to an object and the size of the object. If I'm just adding some tiny UIImageViews, or a couple of UILabels to my view, autorelease keeps the code readable and manageable. And when the view is removed and dealloced, these subviews should get released soon enough.

If on the other hand we're talking about a UIWebView (high risk of autorelease bugs), or of course some data that needs to be persistent till the 'death' of the object, retain/release is the way to go.

Honestly, my projects have not gotten that big yet, where the additional 'staying-time' of autoreleased objects would create a memory problem. For complex apps, that concern is legitimate.

In any case, I don't think a one-size-fits-all approach would be right. You use whatever approach - or combination of approaches - is right for the project, keeping all the factors mentioned above in mind.

Dev Kanchen