Why is autorelease especially dangerous/expensive for iPhone applications?
Asked Answered
H

5

14

I'm looking for a primary source (or a really good explanation) to back up the claim that the use of autorelease is dangerous or overly expensive when writing software for the iPhone.

Several developers make this claim, and I have even heard that Apple does not recommend it, but I have not been able to turn up any concrete sources to back it up.

SO references:
autorelease-iphone
Why does this create a memory leak (iPhone)?

Note: I can see, from a conceptual point of view, that autorelease is slightly more expensive than a simple call to release, but I don't think that small penalty is enough to make Apple recommend against it.

What's the real story?

Halberd answered 5/3, 2009 at 4:37 Comment(0)
G
11

(cannot accept your own answer?)

Well, after all that, I did manage to find a reference from Apple Developer, added as a side-note near the bottom of the page:

iPhone OS Note: Because on iPhone OS an application executes in a more memory-constrained environment, the use of autorelease pools is discouraged in methods or blocks of code (for example, loops) where an application creates many objects. Instead, you should explicitly release objects whenever possible.

Still, this suggests using autorelease carefully, not avoiding it altogether.

(and now for my comment)

It sounds like there is a certain amount of overhead in maintaining the pool. I read this article which would lead me to probably avoid autorelease as much as possible because I prefer things to be consistent. If you have some memory under autorelease and other memory being totally manually managed it can be a bit more confusing.

Gilead answered 5/3, 2009 at 5:36 Comment(8)
happy to help (gave me something to search for :-)Gilead
What they fail to mention is a lot of the classes in Foundation call autorelease on the objects they manage and thus in tight loops you need to create and manage your own autorelease pools if you are processing even a modest amount of data.Lineman
I don't think it's overhead in maintaining the pool; rather, it's best not to have memory allocated but not used any longer than necessary in a memory constrained environment. Autorelease leaves memory allocated longer than necessary.Irkutsk
@Paul, Yeah I thought about that last night on my way home... and then guess I forgot to about updating my answer - good catch.Gilead
The docs DO NOT SAY to avoid -autorelease, they say to avoid NSAutoreleasePool. (See the word "pools" there after "autorelease"?) The reason for this is that when you doing large operations on large sets of data in a constrained environment, using -release is superior because you can more explicitly control the lifetime of the object, thereby freeing more resources for the remainder of your operation. autorelease has extremely little overhead (if NeXT boxes could handle it 20 years ago, so can an iPhone)Landsman
Making use of -autorelease is fine for anything except cases where you're allocating a bunch of objects before the next autorelease pool can be drained. For clarity and succinctness, I use -autorelease almost exclusively, always mindful of the scenarios where it's inappropriate to do so.Obsessive
In practice, you often do not have a choice. For example, if you try to access a large number (30)+ photo assets on the device, the memory-hog UIImage objects only come back autoreleased and you will easily blow your heap. In this scenario you'll need to create an NSAutorelease pool at the begin of each loop iteration (or every n loop iteration if you want to be cute).Thorpe
Can you please link to this apple doc?Bolivia
C
9

It is not the question to use or not to use autorelease, because in some cases autorelease is the only way you'll get through. The question should be "Why not to use autorelease on all objects, instead of using retain and release?".

To answer that, you should first learn what's a proper use for autorelease. Let's say that you have a class that has two properties: firstName and lastName. There is a getter and a setter for each. But you also need a method that would return fullName, by concatenating these two strings into a brand new string:

- (NSString *) fullName {
   NSString str = [[NSString alloc]initWithFormat:@"%@ %@", firstName, lastName];
   // this is not good until we put [str autorelease];
   return str;
}

What's wrong with that picture? The reference count on the returned string is 1, so if you don't want to leak, the caller should release it when he's done. From the caller's point of view, he just requested a property value fullName. He is unaware of the fact that he got a brand new object that he should release after usage, and not some reference to an NSString internally held by the class!

If we put the [str release] before return, the string would be destroyed and the method would return garbage! That's where we use [str autorelease], to mark the object for release at a later time (typically when the event processing is done). That way the caller gets his object, and does not have to worry whether he should release it or not.

The convention is to call autorelease on a new object before the method returns it to the caller. Exceptions are methods with names that start with alloc, new or copy. In such cases the callers know that a brand new object is created for them and it is their duty to call release on that object.

Replacing release with autorelease altogether is a bad idea, since the objects would pile up and clog the memory very quickly, especially in loops. The resources on the iPhone are limited, so in order to minimize memory hogging, it is your duty to release the object as soon as you're done with it.

Cenis answered 6/1, 2011 at 20:51 Comment(0)
E
5

I disagree that avoiding autorelease altogether is wise.

Cocoa Touch uses it quite frequently internally and for many situations it's the only way to allocate memory properly (a good example is reusable table view cells). If you understand what is happening, the autorelease pool is a great tool at your disposal. The main thing to remember is that the blocks are not freed until some point later in the run loop. If you are running a tight loop without user interaction and are piling up autorelease blocks, you will eventually run out of memory.

Autorelease is not a substitute for garbage collection (not available on in the iPhone SDK) and can lead to nasty dangling pointer bugs (the pointer still seems to be good, then at some unpredictable point goes invalid), but is also very useful in writing clear and easy to maintain code. Consider the following case:

[aDictionary writeToFile:
     [documentsDirectory stringByAppendingPathComponent:@"settings.plist"]
              atomically:YES];

The path string is generated as an autorelease object. We aren't required to create a temporary object, so we avoid that overhead (and the possibility we might forget to release it). The memory will be fully released (no leaks), just that it will happen later in the run loop. Ask yourself: am I going to allocate hundreds of these before I get back to user input? If no (as would be the case here), autorelease is a great solution and indeed this NSString method for working with paths is only available using autoreleased memory.

I do agree with the above poster that following convention and being consistent is a very good idea.

Egocentric answered 5/3, 2009 at 20:36 Comment(0)
M
4

I tend to avoid using autorelease on the iPhone where I can (as Jon points out, you can't always do without it), simply because I like to know that the objects I'm working with are released the instant I don't need them. Memory constraints are one of the largest problems you'll face on the device and I believe they're the source of most of the crashing issues you'll find out there.

As highlighted by Apple, a particular area of concern is when you use autoreleased objects within any kind of loop, because they'll pile up within the autorelease pool. You then have to manage when to drain the pool or create / release one. Doing that every pass through the loop might degrade performance, but going too many passes without could lead to dangerous memory usage. I'm still tweaking this in Molecules, because there are intermittent memory issues when importing large (>2 MB) text files from the Protein Data Bank. I was able to improve performance by minimizing autoreleased objects, but couldn't eliminate them completely.

Another area to watch out for is using autoreleased objects with threads. If at all possible, do not use autoreleased objects when dealing with methods performed on a background thread, because the pool can be drained at random times. This leads to intermittent crashes that can be really fun to track down.

Mirna answered 5/3, 2009 at 22:19 Comment(0)
A
0

I would highly suggest avoiding autorelease like the plague. Memory management bugs are a great way to waste massive amounts of time and money, I've had the dubious honor of going through the process many a time on old Mac apps, and the fact that the iPhone has tight memory constraints mean that you have to be extremely careful, or the app will just be unstable and crash often...like so many of the first apps that were released last summer.

The only reliable way I've found to write stable iPhone applications is to manage all your memory yourself, and do it consistently. Even if you are the only programmer on your project, you'll thank yourself later. It can be difficult if you learned to program in languages that "take care of everything for you," but it really is worth learning how to do well if you are serious about createing quality iPhone apps.

Andro answered 5/3, 2009 at 6:16 Comment(1)
-1. You could certainly say it's somewhat less efficient, but autorelease does not create bugs. If you follow the memory management rules (which include autorelease), you won't have memory bugs. If you don't follow the rules, manually releasing things won't save you.Wurster

© 2022 - 2024 — McMap. All rights reserved.