In the following code example from the Core Data Programming Guide, NSFetchRequest is created
with autorelease while NSSortDescriptor is not created with autorelease. Why wasn't NSSortDescriptor created with autorelease? Is it a matter of preference?
NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Employee"
inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];
// Set example predicate and sort orderings...
NSNumber *minimumSalary = ...;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(lastName LIKE[c]'Worsley') AND (salary > %#)", minimumSalary];
[request setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"firstName"
ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
NSError *error;
NSArray *array = [moc executeFetchRequest:request error:&error];
if (array == nil){
// Deal with error...
}
When you autorelease, you're basically saying: "I don't need this any longer, but anyone else is free to pick it up (before the auto release pool is drained)". When you explicitly relase an object you're saying: "I don't need this any longer and unless anyone else has already said otherwise (acquired), it should be deallocated immediately."
Consequently, autorelease is not normally the wrong thing to. It is required when you want to pass objects back to the sender of a message without requiring the sender to take care of releasing the object.
To Autorelease or Not to Autorelease
That is the question.
Whether tis nobler for the coder to suffer the slings and arrows of memory leaks or take arms against a sea of deferenced pointers and by retaining them, end them... Tis a consummation devoutly to be wished! Aye, there's the rub! ... For in those over released objects, what crashes may come when we reference objects that are not there must give us pause.
I couldn't help myself. I'll take the rep hit. I regret nothing!
The request object is going to be returned to the caller, whereas the sortDescriptor is being used and then discarded.
The rationale for autorelease is simple. Without it, any object returned from a function would need to be released by the caller if they didn't need it. Using autorelease means that functions may return an object which if the caller doesn't care about, or if they are going to look at it but not keep a reference to it, then they can just use it without adding additional code to free it. Only if they're keeping a reference do they need to retain it.
It's worth thinking about exactly what autorelease means. When you call autorelease on an object, it adds the object to a list, and when your application loop finishes, it'll have release called on it. This makes autorelease exactly equivalent to a delayed release.
The apple document on memory management is excellent and worth careful reading. http://developer.apple.com/iPhone/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
The question is this: how does the use of autorelease or release affect the lifetime of an object?
In both of your examples it makes no difference.
Both NSFetchRequest and NSSortDescriptors will be alive until the end of the method, regardless of whether they're released or autoreleased.
If you create an instance of an object and then give it to another object (say, an NSArray), it will remain alive regardless of whether you call release or autorelease.
Both retain and autorelease, functionally retain an object but they don't merge. The differences is that retain counts can only be decremented by another object whereas autoreleased counts are decremented automatically when the NSAutoreleasePool is drained. If no other object has retained the autoreleased object by the time the pool drains, it goes poof.
Basically, you use autorelease when you want to make sure an object hangs around in the current method and can be passed to other objects but you don't want to have to track its release yourself.
In your example code, autorelease is just a safety measure. The NSPredicate object is released because its job is finished but the coder wanted to make sure that the NSFetchRequest object hung around. You don't have to use "autorelease" in this instance but if you lost count of your releases the fetchRequest might vanish. On the other hand, you don't want it orphaned and leaking so you use autorelease to clean up when the pool the object is in drains.
The most common use of autorelease is when you are creating a variable number of objects each time. You don't want to have to track them all so you autorelease them and let the pool take care of them. (Even better, you create a local pool and drain it as soon as your done.)
In the Apple API standard, any method that creates a new object without the key words 'init','new' or 'create' returns an autoreleased object.
-[NSString initWithString:] is not autorelease but -[NSString stringWithString:] is. This causes problems in non-Garbage collection environments because stringWithString: returns a string that appears to behave like a retained object but later it will suddenly vanish seemingly at random when the autorelease pool it was created in drains.
Edit01: From the Apple Docs
An autorelease pool is an instance of
NSAutoreleasePool that “contains”
other objects that have received an
autorelease message; when the
autorelease pool is deallocated it
sends a release message to each of
those objects. An object can be put
into an autorelease pool several
times, and receives a release message
for each time it was put into the
pool. Thus, sending autorelease
instead of release to an object
extends the lifetime of that object at
least until the pool itself is
released (the object may survive
longer if it is retained in the
interim).
The retain counts and autorelease both keep an object alive by the same basic (but separate) count mechanism. The major difference is which owning object sends the release. With retained counts, its another object but for an autoreleased count its the autorelease pool.
Related
I am not clear about how to use autorelease;
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
RetainTracker* tracker = [RetainTracker new];
[tracker retain];
[tracker retain];
[tracker autorelease];
[pool release];
Is there any memory leak in the above code?
I know the autorelease just puts tracker into NSAutoreleasePool, without modifying the reference count for tracker. When i call [pool release], the object receives one message release, then the reference count of tracker is 2. So the compiler can't call the dealloc function of object tracker, so there is a memory leak.
So i get this: we shoul call retain and release same times, is it right?
If you're new to Objective-c, you should be using Automatic Reference Counting. Almost everyone should. But for the sake of understanding:
An object has a reference count of how many objects have a reference to it. When it drops to zero, the object is not referenced by anything and is deallocated. Every method in Objective-C is responsible for releasing any object it retains. The problem is, if a factory method's job is to create an object, it's breaking the rules by not releasing an object it retained (in this example it was retained because it was created). If the method called release on the object right before returning it, it would be returning the address to an object that is already gone. So, there is autorelease, which temporarily delays the release until the calling method can retain the object the called method created.
In your example above, if you got rid of the 2 retains, and only called autorelease, then the object would get released and deallocated when the autorelease pool is released and (right before deallocation) is drained, meaning it calls release on all objects in its pool, tracker being one of them because calling autorelease on tracker added it to the pool.
new is equivalent to doing an "alloc" & "init", so retain count on tracker on that line is 1.
Then you increment the retain count 2 more times to give a total retain count of 3.
Autorelease sets the tracker to be released when the pool is released (and the retain count is decremented as well). But it's already retained 3 times, so it doesn't really get released.
And yeah, there is a memory leak with the retain count being greater than 0 and no reference to "tracker" outside of that method (that is, unless you're using "tracker" in an instance variable).
It's very good to know the basics of memory management; but if you want to save yourself a ton of headache, just do what everyone else here seems to be saying and simply enable ARC.
EDIT: And to finish your question, you should make sure every call to retain is balanced with a release. You also do a "new", which also increments the retain count so you need to "release" because of that as well.
I have Util class as follows.
#implementation Util
- (NSString*) getTodayString
{
NSDate *today = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
// display in 12HR/24HR (i.e. 11:25PM or 23:25) format according to User Settings
[dateFormatter setDateFormat:#"YYYY/MM/dd"];
NSString *now = [dateFormatter stringFromDate:today];
[dateFormatter release]; ///???
[today release]; //???
return now;
}
#end
And I use the class
- (void)awakeFromNib
{
Util *ut = [[Util alloc] init];
NSString* now = [ut getTodayString];
NSLog(#"User's current time in their preference format:%#",now);
[currentTime setObjectValue:now];
[now release]; ///???
[ut release];
}
I'm confused when releasing objects.
In getTodayString ::
Q1. [dataFormatter release] is necessary?
Q2. [today release] is necessary?
I guess I don't need to release them as I didn't alloc myself. If that's true, when those objects are released?
In awakeFromNib ::
Q3. [ut release] is necessary?
Q4. [now release] is necessary?
I guess I have to release ut as I create the object explicitly, but not suer about now object.
How one can determine when is the object is released?
With python/C#/Java one doesn't care about this kind of deallocation of memory anymore. Is it also OK with Objective-C if I don't care about them?
Q1. [dataFormatter release] is
necessary? Q2. [today release] is
necessary?
dataFormatter: yes, you alloc/init'd it.
today: no, it was returned autoreleased from a factory method.
Q3. [ut release] is necessary? Q4.
[now release] is necessary?
The same,
ut: yes, you alloc/init'd it.
now: no, it was returned autoreleased from a factory method.
How one can determine when is the
object is released?
it's released when release is called on it, if autorelease is called, release will be called during the next run of the Autorelease Pool.
Is it also OK with Objective-C if I
don't care about them?
No, it's not ok. If you do not clean up after yourself you will have substantial memory leaks, in the iOS environment that means a quite shutdown of your app. In a Mac app that can lead to eating up a ton of memory and not being a good citizen. This is assuming a non garbage collection environment. Ie most.
I'm guessing the heart of your question is you aren't sure when you are responsible for calling release and when you get an autoreleased object (or rather, when you are responsible for calling release on the object). It's by convention. If you call any method that returns an object that does not contain the words: init/copy then it is not your responsibility to call release. If you retain, you release (There may be some more rules to follow, but that's the first one to really start understanding this, in my opinion). If you ever call alloc/init/copy, then you must call release at some point.
A GREAT teacher is Build & Analyze in Xcode. This will quickly point out where you screwed up and really help to understand what is going on.
Whether or not you care about memory management in objective-c depends on the environment you are using. If you are using garbage collection, you don't have to worry about it, but garbage collection is not enabled by default on the mac and is not available at all on iOS. Basic rules for when something needs to be released:
If the method you get it from starts with alloc or init, or contains the word copy, then you own it and must release it.
If you explicitly retain an object, you own it and must release it.
If the method does not contain alloc, init, or copy, you can assume it has been autoreleased. It will be released automatically at some point in the future, and you need to retain it if you want to use it after the current method returns.
Of course those also depend on any third party code following those rules with when they autorelease returned objects.
The memory management rules are simple and clear. Do not think in terms of retain counts, always think in terms of ownership. When you ask yourself the question “should I release this object?”, ask yourself “do I own it?”. Commit the rules to memory, and eventually they will become second nature.
It is extremely important that you follow the rules. If you ignore them, objects that you don't own may be deallocated before you are done with them (such as assigning objects that you don't own to instance variables, they may become deallocated after the autorelease pool is drained). Also, if you ignore them, you will end up with horrendous memory leaks.
3 correlated questions:
1.Do the code snippets below provide the very same results in terms of memory?
NSBundle *bundle=[[NSBundle alloc] init];
[bundle release];
bundle=nil;
and
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
NSBundle *bundle=[NSBundle mainBundle];
[pool drain];
pool=nil;
bundle=nil;
2.Why in
NSBundle *bundle=[[NSBundle alloc] init];
[bundle release];
the retainCount of bundle is 1, not 0?
3.Which is recommended: always use class methods, or always gain ownership by using alloc?
Thanks.
Yes, those should be equivalent in terms of memory management, from the developer's point of view. The frameworks might be doing something behind the scene to hang on to [NSBundle mainBundle], but that's not your concern.
Ignore retainCount. waves hand That's not the method you're looking for. Once you have relinquished ownership of an object, either by invoking release or autorelease, then it is invalid (bad practice) to send more messages to that object. In your example, you alloc an NSBundle, so you own it. That means it has a +1 retain count (I say +1, because it's relative). When you release the bundle, it now has a "0" retain count, which means you no longer own this object (despite whether or not it may still exist in memory), which means you should not send messages to it, under penalty of stuff blowing up in your face.
What's recommended is to use whatever's appropriate for the situation. If you just need a temporary object, then using a class method that returns an autoreleased object is probably going to be just fine. If you need to be absolutely sure that the object isn't going to go away while you're using it, then you can use an alloc/init approach (or retain an autoreleased object) and then just release it when you're done.
In the second example you will create 1 extra object (the NSAutorealeasePool) and because of that the two are not exactly the same in terms of memory. But after the code runs I believe the memory will return to the same state in both examples. I am not really sure but I believe that in the second example bundle is an autoreleased object, so when the pool is drained it gets released.
I believe that when the object gets dealloc'ed the retainCount isn't changed.
It is usually recommended to avoid class methods when you create a lot of temporary objects because they won't get released until the next AutoreleasePool drain is called (and if you don't have an AutoreleasePool inside your method it won't happen for sure until you return from your method - and maybe even later). Otherwise you should use the one that feels better for you. I personally prefer allocating them. It is also important to remember that if you want the autoreleased object (the one returned from a class method) to stick around even after you return from the function to retain it.
I still have some unclear understand about release and autorelease. What are the difference between both of them? I have this code. For facebook connection. I crash it sometimes when I go to Facebook login, I doubting maybe it is because I don't release the object nicely.? Thanks for any helps
if (_session.isConnected) {
[_session logout];
} else {
FBLoginDialog* dialog = [[[FBLoginDialog alloc] initWithSession:_session] autorelease];
[dialog show];
}
The Memory Management Programming Guide for Cocoa will soon be your best friend. In brief, object instances in Cocoa are memory managed using reference counting (unless, of course you're using garbage collection on OS X). An object indicates that it wants to 'retain' an ownership interest in an other instance--keep it from being deallocated--by sending it a -retain message. An object indicates that it wants to release that interest by sending the other instance a -release message. If the number of objects that have 'retained' and ownership interest in an object drops to 0 (i.e. when the last of the owning instances sends a -release message), the instance with a 0 retain count is deallocated.
It's sometimes convenient to say "I want this instance to be released some time in the future". That's the purpose of -autorelease. Sending an -autorelease message adds the receiver to the current NSAutoreleasePool. When that pool is drained, it sends a -release message to all the instances in the pool. An NSAutoreleasePool is automatically created at the start of each iteration of each thread's run loop and drained at the end of that iteration. Thus, you can do something like this in a method:
- (id)myMethod {
return [[[MyObject alloc] init] autorelease];
}
The caller of this method will get back an instance that they can -retain if they wish to keep it. If they don't retain it, it will stick around at least until the enclosing autorelease pool is drained:
- (void)someOtherMethod {
...
id instance = [obj myMethod];
... // do more with instance, knowing that it won't be dealloc'd until after someOtherMethod returns
}
Releasing means you release that right away.
Autoreleasing means you want the variable to be released on the next autorelease pool.
You use autorelease when you want to keep retaining the variable but don't want to create a memory leak. You use release when you don't need the variable anymore.
Sample:
- (NSNumber *)return5 {
NSNumber * result = [[NSNumber alloc]initWitnInt: 5];
[result autorelease];
return result;
}
Why do we use autorelease there?
If we use [result release] instead, variable result will be destroyed AT that time. Which means that the returned value will be garbage.
If we do not release at all, variable result will be hold FOREVER incurring memory leak.
We can tell every caller to the function to release result but that would be a headache and prone to error.
So we use autorelease. We mark the variable to be released on the next autorelease pool. Basically we mark the variable to be released near the alloc. Hence the mantra alloc is paired with release in the same function holds all the time.
Actually, you'll do fine changing all release into autorelease. Your memory use won't be efficient, however, the effect is minimal. All variables, in all programming language is effectively autoreleased.
Anyway, use ARC.
background discussion:
objective-c is reference counted, so objects are deleted when the reference count reaches 0. release reduces the reference-count immediately, autorelease reduces it when the autorelease-pool is popped
when to use:
use autorelease when allocating the object if
you do not need it after the current function
it will be retiained by some other objet/function and will be released by a later by the retaining code
when the logic of the current function is tricky, so you would have to send release in a dozen different places before doing a return
use "manual" release
to revert a previous retain (in case you are implementing a library)
if you need precise control of freeing objects (e.g. they use lots of memory or the autorelease pool will not be popped for some time)
but really my freand:
read the Memory Management Programming Guide for Cocoa as suggested by Barry and run your code with instruments (zombies and leaks) often to catch any and almost all memory management errors.
Erik
According to the Memory Management Programming Guide for Cocoa:
The autorelease method, defined by
NSObject, marks the receiver for later
release. By autoreleasing an
object—that is, by sending it an
autorelease message—you declare that
you don't want to own the object
beyond the scope in which you sent
autorelease.
Also:
The autorelease method thus allows
every object to use other objects
without worrying about disposing of
them.
Here is the gist of some code I'm writing. I'm concerned that I am not properly addressing the retain/release issues with the array class method on NSMutableArray. Is the following actually leaking memory?
for(a while) {
// do stuff
NSMutableArray *a = nil;
// do stuff
if (!a) {
a = [NSMutableArray array];
}
} // for(a while)
You wouldn't leak memory in this code, and releasing the array yourself will cause a crash when the array is autoreleased at the end of the run loop.
Most Cocoa classes provide a couple of ways of making a new object, and are very consistent with this convention:
[[NSSomeObject alloc] init] : you are responsible for releasing the object (instance method).
[NSSomeObject someObject] : the object will be autoreleased for you, usually at the end of the run loop (class method). It's roughly equivalent to [[[NSSomeObject alloc] init] autorelease].
The proper use of the instance method would be:
a = [[NSMutableArray alloc] init];
// do stuff
[a release];
The proper use of the class method would be:
a = [NSMutableArray array];
// do stuff, array is in the autorelease pool
Note that Apple has recommended you stay away from the convenience methods as much as possible to improve performance. This is controversial advice, may not save much processor time, and separates the alloc-init from the release on an object you may not actually care much about keeping.
From the Cocoa Memory Managment Rules:
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.
Therefore with the line:
a = [NSMutableArray array];
you do not take ownership of the array, and it will be passed to you autoreleased. The memory will be handled for you automatically by the autorelease pool, and once it is no longer being used, it will be released for you. If you want to keep the array outside the current event, however, you must retain it, otherwise it will be released for you.
Yes, if you want it to stick around.
The returned object is an autoreleased object which will get deallocated when its autorelease pool gets purged.
All the array class methods that begin with "array" return these types of autoreleased objects.
Read this doc by Apple.
That's valid. It may help to just manage things manually when you have questions, to learn.
There is a convention:
init prefixes (init, initWithString:) indicate a retain count of 1, where
objectname prefixes (string, stringWithString:) indicates an autoreleased object
I have had the habit, for years, to release what I can at the call site, rather than pushing it to be autoreleased. Some autorelease issues then become painfully difficult to track down. Sure, autorelease is a convenience to the programmer in this case (provided nothing goes wrong), but adversely affects reuse, clarity, and performance (moreso in large codebases/programs).