Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

ryans79

macrumors regular
Original poster
Apr 12, 2009
226
0
Hey again!

Did a lot of reading (thanks to you guys helping me with links) and went through that screen cast for memory management in Objective -C again.

Its a bit clearer now, except i have a slightly (maybe silly) question about one part that confuses me.

Whats the diff between Release and Autorelease?

I think the above should also answer the below, but if not:
Why cant i always do an autorelease instead of a release?

°°
Ryan
 
In terms of correctness you can always use an autorelease instead of a release. Autorelease is a delayed release. It schedules the object to receive its release at a later time.

The reason to use release instead of autorelease is that autoreleased objects hang around for a while in memory. Released objects are gone immediately. If you have a loop that generates thousands of autoreleased objects it's possible to use too much memory. On a desktop computer this is almost never a problem. On the iPhone it might be a problem.

There are a number of framework methods that return, for instance, autoreleased strings. These methods are very convenient when doing string manipulation. Most of the time I just them and don't even feel guilty. However for many kinds of temporary objects you can easily alloc/init, use the object, then release. This avoids an over use of memory and is considered the right way to do things on iPhone OS.
 
...assuming nothing else is retaining it, of course. :)

Of course. But if something else is retaining it then there's less advantage (probably) to release over autorelease.

Here are a couple common idioms

Code:
object = [[Object alloc] init;
// use object
[object release];

object = [[Object alloc] init;
[array addObject:object];
[object release];

In the first case the object is created, used, and then released, which deallocs the object. In the second case the object is created and ownership of the object is transferred to the array. Releasing the object in the second case completes the transfer of ownership but the object won't be dealloced until it's removed from the array or the array itself is dealloced. You could use autorelease in both these cases but it isn't required so it's not a good idea.

OP asked for the difference between release and autorelease but I guess I'm answering the question 'when should one use one vs the other.' In short, use release when you can and autorelease when you must. When the useful lifespan of the object is over use release, or if you have completely transferred ownership you could use release. Use autorelease when you return an object from a method. This is to satisfy the memory management rule that an object that creates another object must also release it. But of course in this case you don't want the object to be dealloced yet, even though you're returning it from a method and the method doesn't have any more use for it.
 
But you also don't want to get hung up with choosing between releasing and autoreleasing an object based on what you think is better in terms of memory/performance. For most apps, 99% of the time autorelease is fine. Once you start to write tight loops somewhere then you'll want to consider adding your own autorelease pools, and even then autorelease is still fine. Also, using autorelease convenience methods provides cleaner and easier to read code, so if you're finding yourself alloc/initing all the time with your custom objects, consider adding a an autorelease class method.

My 2¢
 
Thanks for replying guys!

There are a number of framework methods that return, for instance, autoreleased strings. These methods are very convenient when doing string manipulation.

Since i am just following a book and screencast examples my vision has been quite limited to what i read and see in the screencast, can you give me some links or hints about those "autoreleased strings" so that i may read up please?

@PhoneyDeveloper,
In your second array example, after the object ownership has been transferred, you would use the autorelease in the dealloc method there, right? or have i got it wrong?


you'll want to consider adding your own autorelease pools,
Hmmm, i think thats a bit way to advanced for me as i have not come to that in the book or the screencast, right now it does not make much sense to me,but will keep it in mind as i'm sure it will turn up.


if you're finding yourself alloc/initing all the time with your custom objects, consider adding a an autorelease class method
You wouldnt happen to have a sample of this would you?

Cheers!
°°
 
I, personally, think that you shouldn't use autorelease if it's not necessary. In my opinion, if you know you don't need an object anymore, then releasae it - why should you autorelease it if there is no need for that? it's bad coding style in my opinion.

you really NEED autorelease when, for example, you want to return an object. let's say you have a method:
Code:
-(void)something:(int)anIntNumber {
    NSNumber *anNSNumber = [[NSNumber alloc] initWithInt:anIntNumber];
    return [anNSNumber autorelease];
}
the reason to use autorelease here is very simple: you created the object, so you are responsible for it. after returning the object, you are done with it in the method "something" so you need to release it. BUT: if you use "release", the object is released immediatly, which means you cannot return it (because it doesn't exist anymore). so you use autorelease, which allows you to return it and it allows whoever receives the object to use and even retain it, which will prevent the object from getting destroyed when it finally gets the release message. sometime after that, when the receiver has done everything it needs with the object, the autorelease pool is emptied and the object gets a release message.

almost every other time there is no need for autoreleasing, so simply make good memory managment and release your objects if you are done with them!
 
In your second array example, after the object ownership has been transferred, you would use the autorelease in the dealloc method there, right? or have i got it wrong?

You don't have to release or autorelease the object in that case. It will get released implicitly once the array is emptied (in case of NSMutableArrays) or released. In other words: Releasing that object is the array's problem, not yours.

BTW, I don't think it's helpful to think of these things as "ownership", which can be "transferred". Any given object can have lots of different owners at the same time. Also, object A may retain object B more than once.

But personally, I like real-world metaphors, too. Here's what I do: I think of retaining as a kind of popularity contest. Objects get dealloc'ed when no other object likes them anymore, i.e., when all of the objects that once alloc'ed and/or retained them have released them fully.

You wouldnt happen to have a sample of this would you?

Here's the basic concept:

Code:
+ (SomeObject*)someObjectConvenientlyReturnedAsAutoReleased {
	return [[[SomeObject alloc] init] autorelease];
}

However, you'll usually do this within SomeObject's implementation, so you'd rewrite it as:

Code:
+ (id)someObjectConvenientlyReturnedAsAutoReleased {
	return [[[self alloc] init] autorelease];
}

Doing it this way comes with two subclass-related advantages:

1. If you're referring to the class as "self" instead of hard-coding it as "SomeObject" when allocating, subclasses of SomeObject (e.g., SomeObjectDerivative) will work as expected and return objects of the subclass type.

2. By returning a result of type "id" (read: "any NSObject or NSObject subclass") instead of "SomeObject", you avoid the compiler warning you'd otherwise get for doing something along the lines of ...

Code:
SomeObjectDerivative *object = [SomeObjectDerivative someObjectConvenientlyReturnedAsAutoReleased];

... with SomeObjectDerivative being a SomeObject subclass, as mentioned above. Otherwise, you'd have to do an explicit typecast, which I, personally (again ;)), consider ugly.
 
almost every other time there is no need for autoreleasing, so simply make good memory managment and release your objects if you are done with them!
I have to agree with BlackWolf. Since memory is tight on the iPhone, it's a good practice to be diligent with your memory management and just release when you know you no longer need an object.

Think of it this way: release says "i'm done with this right now" and autorelease says "i'll be done with this later and i'll let the OS decide when to release it".
 
Think of it this way: release says "i'm done with this right now" and autorelease says "i'll be done with this later and i'll let the OS decide when to release it".

As kainjow mentioned, that's only true as long as you don't create your own autorelease pools. (But even then, it's pretty much your decision when you let the app return to its main run loop.)

But there will always be a trade-off between saving memory and staying on top of your code. Some developers just find it easier to work with autoreleased objects returned by convenience methods, because that means less need for active balancing of retain and release messages, and because it makes their code shorter and thus, more legible. Besides, kainjow definitely has a point when he says that in most cases, it really doesn't make much of a difference.

From my expierience, lots of aspects in Mac and iPhone programming boil down to simple matters of taste. Once you understand what's going on, you can make your own informed decision. :)
 
In your second array example, after the object ownership has been transferred, you would use the autorelease in the dealloc method there, right? or have i got it wrong?

No, once ownership is transferred there's nothing more to do. The object was created in a way that provides ownership. alloc creates an object that is retained. When adding the object to the array the array retains it. Ownership is now shared. By explicitly releasing it on the third line the class that created the object gives up ownership. There's nothing more to do. The alloc has been balanced by a release. The array has retained the object and will eventually release it also. While there might be a reason to use autorelease in this case usually there is not. Usually this class owns the array so it has an indirect ownership of the objects in the array. When the array is released or objects are removed from the array then they will be released and usually dealloced.

Ownership is an important concept. All objects must have owners. While autorelease is a way to have a deferred release it is implemented by transferring ownership of the object to an autorelease pool.

When writing code in most cases you just have to follow the memory management rules correctly and things will work correctly. The big picture though is that your app is a tree of object ownership. Every object has an owner that is responsible for releasing it. The root of the tree is the application object. It owns the app delegate. The app delegate will own various other objects that your code creates. The only objects that might not be specifically owned would be local variables in the current leaf method.

So there is a tree of ownership whose branches continue down from the app delegate to view controllers and their views and any other objects that the view controllers own. It is possible to have global objects or singleton objects (which are a kind of global) that are independent roots and also have their own tree of ownership.

Any objects that aren't part of this tree of ownership are memory leaks, which is a coding error.

Autorelease pools are a handy chaperone that allows objects to be owned temporarily so they can be passed around without being part of the application tree of ownership.
 
Thanks for sharing your opinions, everyone.

I guess if I am less inclined to deal with memory leak, I can simply wrap autorelease around objects and let the pool deal with it.
 
Measure and then don't bother!

If your app doesn't allocate objects inside unbounded loops or recursion, and the peak limit of such allocations is less than most other typical apps require, the other unmentioned alternative is to just not bother to release anything. Xcode includes great tools to measure peak memory allocation, and a lot of dealloc methods are never ever called even when the app is terminated. Your app can purposely leak 5 or 10 MB of memory, and still use and require far less memory than the median game. So, why bother?

(Actually, I will bother. When contracting by the hour, I usually promise clean code using best coding style and practices. Adding all the (useless) matching releases allows me to charge a lot more, given nearly twice as many lines of memory management code. $$$ :)


ymmv.
 
If your app doesn't allocate objects inside unbounded loops or recursion, and the peak limit of such allocations is less than most other typical apps require, the other unmentioned alternative is to just not bother to release anything. Xcode includes great tools to measure peak memory allocation, and a lot of dealloc methods are never ever called even when the app is terminated. Your app can purposely leak 5 or 10 MB of memory, and still use and require far less memory than the median game. So, why bother?

(Actually, I will bother. When contracting by the hour, I usually promise clean code using best coding style and practices. Adding all the (useless) matching releases allows me to charge a lot more, given nearly twice as many lines of memory management code. $$$ :)


ymmv.

people, c'mon, what the hell? don't give tips like that to new developers.
just because it WORKS doesn't meed you SHOULD.
 
and a lot of dealloc methods are never ever called even when the app is terminated.

No, dealloc methods are never called only when the app is terminated. The reason for this should be fairly obvious.

Justify it how you want; deliberately leaking memory is a terrible idea, and a very bad habit to cultivate. In the real world apps don’t run for fixed lengths of time and without user input, so you have no way of knowing whether there’s going to be enough memory to hold all the garbage you allocate throughout the life of the app.
 
... so autoreleasing isn't as ideal for iPhone memory as allocating, initiating and then releasing, but isn't it more processor intensive to perform the later? is it simply a give and take situation?

would you say that if an app is very light on the processor, alloc/init/release would be ideal, but if i have an app that's crazy flashy graphics and processor intensive, wouldn't it be more ideal to rely on autorelease instead?

what is the processor/memory usage ratio with something like the following:

Code:
//Attack Processor

- (IBAction)buttonPressed:(id)sender
{
	NSString *title = [[NSString alloc] initWithFormat:[sender titleForState:UIControlStateNormal]];
	NSString *newText = [[NSString alloc] initWithFormat:@"%@ button pressed.", title];
	[title release];
	statusText.text = newText;	
	[newText release];
}

Code:
//Attack Memory

- (IBAction)buttonPressed:(id)sender
{
	NSString *title = [sender titleForState:UIControlStateNormal];
	NSString *newText = [NSString stringWithFormat:@"%@ button pressed.", title];
	statusText.text = newText;	
}

i guess i'm trying to ask what is generally more of a precious resource on the iPhone platform: memory or cpu.
 
... so autoreleasing isn't as ideal for iPhone memory as allocating, initiating and then releasing, but isn't it more processor intensive to perform the later? is it simply a give and take situation?

would you say that if an app is very light on the processor, alloc/init/release would be ideal, but if i have an app that's crazy flashy graphics and processor intensive, wouldn't it be more ideal to rely on autorelease instead?

what is the processor/memory usage ratio with something like the following:

Code:
//Attack Processor

- (IBAction)buttonPressed:(id)sender
{
	NSString *title = [[NSString alloc] initWithFormat:[sender titleForState:UIControlStateNormal]];
	NSString *newText = [[NSString alloc] initWithFormat:@"%@ button pressed.", title];
	[title release];
	statusText.text = newText;	
	[newText release];
}

Code:
//Attack Memory

- (IBAction)buttonPressed:(id)sender
{
	NSString *title = [sender titleForState:UIControlStateNormal];
	NSString *newText = [NSString stringWithFormat:@"%@ button pressed.", title];
	statusText.text = newText;	
}

i guess i'm trying to ask what is generally more of a precious resource on the iPhone platform: memory or cpu.

of course it depends on the app you're building, but generally memory is very limited on the iphone.
though I don't really see why autoreleasing should cause less cpu usage.
 
... so autoreleasing isn't as ideal for iPhone memory as allocating, initiating and then releasing, but isn't it more processor intensive to perform the later?

No, autoreleasing is in fact slightly more processor-intensive as well as more memory-intensive. The object is still allocated, initialised and eventually released — autorelease adds a little extra overhead by delaying the release.

Having said that, of the two examples you give I would prefer the second, for the simple reason that it’s more concise. Less code is almost always better code. For a one-off method like a button push the performance implications of the autorelease are negligible. I’d only go for the more verbose option in tight loops or other situations in which performance profiling has indicated there’s serious room for improvement.
 
... In fact, I’d do it like this.

Code:
- (IBAction)buttonPressed:(id)sender
{
	statusText.text = [NSString stringWithFormat:@"%@ button pressed.", [sender titleForState:UIControlStateNormal]];
}

IMO variables should only be used for values which change, as a general rule.
 
No, autoreleasing is in fact slightly more processor-intensive as well as more memory-intensive. The object is still allocated, initialised and eventually released — autorelease adds a little extra overhead by delaying the release.

Having said that, of the two examples you give I would prefer the second, for the simple reason that it’s more concise. Less code is almost always better code. For a one-off method like a button push the performance implications of the autorelease are negligible. I’d only go for the more verbose option in tight loops or other situations in which performance profiling has indicated there’s serious room for improvement.

while autoreleasing may be less code, it's still untidy code because you keep an object around from which you know you don't need it anymore.

but in the end, in almost any situation this is more of a taste decision ... it doesn't really affect performance.
 
i use autorelease only when returning an object from a function, but i think in most cases both are fine
 
... so autoreleasing isn't as ideal for iPhone memory as allocating, initiating and then releasing, but isn't it more processor intensive to perform the later? is it simply a give and take situation?

would you say that if an app is very light on the processor, alloc/init/release would be ideal, but if i have an app that's crazy flashy graphics and processor intensive, wouldn't it be more ideal to rely on autorelease instead?

what is the processor/memory usage ratio with something like the following:

Code:
//Attack Processor

- (IBAction)buttonPressed:(id)sender
{
	NSString *title = [[NSString alloc] initWithFormat:[sender titleForState:UIControlStateNormal]];
	NSString *newText = [[NSString alloc] initWithFormat:@"%@ button pressed.", title];
	[title release];
	statusText.text = newText;	
	[newText release];
}

Code:
//Attack Memory

- (IBAction)buttonPressed:(id)sender
{
	NSString *title = [sender titleForState:UIControlStateNormal];
	NSString *newText = [NSString stringWithFormat:@"%@ button pressed.", title];
	statusText.text = newText;	
}

i guess i'm trying to ask what is generally more of a precious resource on the iPhone platform: memory or cpu.

I'm no expert, but from what I've been reading in books and learning from the Stanford iPhone course, the former is what you want. The advice I've picked up is that it's best to not rely too much on convenience methods that return autoreleased objects, as they are a bit more taxing on memory. I almost always use alloc/init whenever possible, use the object in some way (which is usually retained by whatever you're using it for), then release it.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.