I have a general idea on how NSAutorelease pool works.
we have objects in it which are autoreleased and when the drain method is called.
the pool is checked for objects with retaincount as +1, and are thus deallocated.
but what I am not sure of is.
We create object of NSAutoRelease pool in the main thread as well as one for each thread.
How is a thread related to that particular pool.
What happens if we create two or more autorelease pools in one thread.
we just create the pool object and drain it when our work is done.
its not like that we get a singleton or something .
Then how does the thread get to that particular pool ?
Explanation of the scenario of what I mean by retain count 1. [slightly incorrect, read the edit]
Obj A has a method createAndReturn.
createAndReturn creates an object autorel_obj and returns it.
Now it can't just release it as it has to return it.
So it will autorelease it and return.
Thus autorel_obj will be in autorelease pool.
now say objB calls createAndReturn of ObjA.
and gets hold of autorel_obj and retains it otherwise autorelease pool will drain it.
Now when it is being retained by objB, its retain-count is 2.
[Here is the incorrect part corrected in, the EDIT]
Autorelease pool just cant release autorel_obj until it is also being used by objB also.
thats why until objB also releases it and its retain count becomes '1', it cant be released.
so By retainCount 1, what I mean is that the object which sent it to the pool is the only one owning it.
and regarding pool and thread relation, Firoze Lafeer answer was helpful.
EDIT to retain count 1 scenario:
As correctly pointed out by Firoze,
My earlier explanation of retain count 1 needs a change.
autorel_obj will only be released when pool is drained and hence its retain count will go down by 1.
It wont be deallocated from memory.
Once every other owner obj of autorel_obj releases it and its retain count becomes 0.
then only it is deallocated from the memory.
Sorry for all the trouble, Thanks to Firoze for the correction.
the pool is checked for objects with retaincount as +1, and are thus deallocated.
I'm not sure I understand that statement completely, but it sounds incorrect to me. There is nothing conditional about autorelease. If you autorelease an object, it will be released when the pool is drained, regardless of its retain count at that point (even if the object had already been deallocated!) It's better to think of "autorelease" as "deferred release".
As for the other question, each thread maintains its own stack of autorelease pools. Each pool is associated with one (and only one) thread.
Which thread is a given pool associated with? The answer is whichever thread created the pool. If you create a new pool where one exists already, then the new pool is "nested" within the existing pool. Objects autoreleased within the scope of that new pool will be released when that pool is drained (when the scope of that pool ends).
I hope that helps?
EDIT
To address your edit:
Your explanation is not correct. The autorelease pool can and does release the object as soon as it is drained. It doesn't wait for objB to release it first. It doesn't even know what other objects may have retained autorel_obj from your example. I think you're confusing release with deallocation.
So the scenario is this:
createAndReturn allocates and autoreleases autorel_obj (retain count is +1)
objB retains autorel_obj (retain count +2)
pool is drained, autorel_obj is released by the pool (retain count +1)
at some point in the future, objB releases autorel_obj (retain count 0)
autorel_obj is deallocated
So, again, the pool doesn't know and doesn't care what other objects may have retained the object it is releasing. It does the release, unconditionally, when drained. That may not cause the object to be deallocated immediately, but that's not the pool's concern.
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'm still not 100% with ARC internals.
A few examples that I would like clarified:
What happens with someObjectToReturn = [[SomeClass alloc] init]; that is allocated inside a method and returned? If someObjectToReturnis assigned to e.g. someObject, when will someObjectToReturn be released? When someObject is nilled or does someObjectToReturn still need to be added to an autorelease pool?
Another case is if an array of objects is nilled, are all the objects released?
Lastly, where is a good place to release a copied block object? Or will the block still be released after execution? If the copied block is added to an autorelease pool, when would one drain that pool?
Lets say there are 10 blocks, each added to an autorelease pool, draining it too soon would result in the executing blocks to die. Can a copied block be nilled from within itself, such as dispatching the nilling of the block back to the main thread?
You seem to be overcomplicating things. Under ARC, you can't release objects, or drain autorelease pools, so there is no "right" time to do this. Don't think about retain and release and autorelease (except in tight loops), think about object ownership.
Your specific questions:
The object will be released when the variable that the return value is assigned to goes out of scope or is set to nil. You don't have to worry about it.
Yes, all the contents of an array are released when the array is set to nil, you don't have to worry about it
You can set the value holding the copied block to nil when you're done, or it will disappear when the object owning the copied block goes. You can't drain an autorelease pool under ARC, you can wrap statements in an #autoreleasepool{} block, but this just captures everything in the block - you don't "add" things to the pool or "drain" the pool.
What prevents the autoreleased instance of NSArray from being released before it's used in the method it's returned to?
- (NSArray *) f {
return [NSArray array];
}
- (void) g {
NSArray *a = [self f];
// do something with a
}
What prevents the autoreleased instance of NSArray from being released
before it's used in the method it's returned to?
Autorelease pools are per thread. That is, an autoreleased object is, effectively, a delayed call to release that happens on a per thread basis.
Thus, if there is no call to drain between the caller and the callee, there is no way the autoreleased object will be released because of a pool drain (barring serious threading stupidity).
In general, pools are drained at very well specified times, like Kevin said:
• the run loop will drain the pool at the bottom of each pass through the loop
• dispatched blocks via GCD will execute within a pool context that'll be drained "every now and then" (implementation detail). NSOperationQueue behaves similarly
• other threads are responsible for doing it themselves
Thus, in your simple example, the code execution is quite linear and, by inspection, there can be no drain in that thread of execution between the return and the use in the caller.
(Note that this is also one of the reasons why retainCount is useless; it neither accounts for any "delayed release" calls caused by autorelease nor does it quantify any per-thread retains. In reality, you should think of retains/releases as being entirely per-thread; if you retain an object on a thread you should release it on the same thread unless you are explicitly transferring ownership from one thread to another.)
Autoreleased objects are only released when their surrounding pool is drained. This is not some magical process that happens behind the scenes. It's a deterministic event that happens at well-defined times. In general, the pool is drained when control returns to the run loop. If you establish your own nested pool, then you control when that drains.
The autorelease pool is drained during an iteration of the event loop. Since it's that drain that causes release messages to be sent to the autoreleased objects, they are still valid in the calling method.
Is there a way to change an autoreleased object to one that is non-autoreleased?
NSCoder's decodeObjectForKey returns an autoreleased object, which messes with a couple memory systems in my app. How can I change its returned value to a non-autoreleased object?
I know I can run retain on it, but if I release it, it'll still remain autoreleased. Whereas, I want to manage the memory myself.
Set up an autorelease pool before you retrieve the autoreleased object. It will be in that autorelease pool. Retain the object. Now release the autorelease pool. Your object is no longer in an autorelease pool. It's retained, and it's now your responsibility to release 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.