Whenever we are calling autorelease method, its object is going to NSAutoreleasePool. When the pool is drained, it is sending release to all the objects in the pool.
My question is;
In the main function there is one NSAutoreleasePool. I want to know that; when we call the autorelease method, where it is sending the object ? I mean; it is sending the object to NSAutoreleasePool which is in main function (or) somewhere ?
Thanks in advance.
There is actually a stack of autorelease pools. Whenever you do [[NSAutoreleasePool alloc] init] that newly created pool is automatically put on top of the autorelease pool stack. You can create your own pools whenever you need it.
To be more precise: there is a stack of autorelease pools on each thread. So whenever you create a thread (for example with [foo performSelectorInBackground:#selector(bar) withObject:baz]) the very first thing you need to do is create a pool or else your objects leak (this creates the infamous messages like "NSAutoreleaseNoPool(): Object 0xd819d0 of class NSCFString autoreleased with no pool in place - just leaking" and is a very frequently asked question here on SO).
When you call autorelease, the object is registered with the top-most autorelease pool of the current thread (that is: the one that was created last on that thread). The main run loop has its own autorelease pool that is emptied on each run loop iteration (AFAIK). The pool from main.m is there to catch any objects that for example might be generated internally by Cocoa Touch before it gets to create the run loop autorelease pool.
Edit: For more behind-the-scenes information, see Mike Ash's "Let's Build NSAutoreleasePool"
Related
Hey, I am making a cocoa touch static library, And I have this problem:
I am running my project in the simulator with the Leaks instrument, And I am coming up with leaks for autoreleased objects.
I know for a fact that I have at least one NSAutoreleasePool in place at a time (in my main() method), my question is, how often should I put in others (I am developing for iPhone and iPad if that matters)
UPDATE: I have figured out that, for some reason, my code isn't exiting out of the UIApplicationMain() call on iOS 4, I am just getting a SIGKILL signal, and my autorelease pool isn't draining. How can I fix that (I mean the app getting a SIGKILL)
Thanks
NSAutoreleasePool is required when you run something in a background thread, so if your functions can be run in a background then you need to create a autorelease pool in them:
- (void) willRunInBackground{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
...
[pool drain];
}
The second situation where NSAutoreleasePool will be useful is when you create many autoreleased objects in a loop - to avoid to much autoreleased objects hanging around you can create and drain autorelease pool on loop iteration (as Joe mentioned).
But you memory leaks are likely caused by the 1st reason - each thread must have its own NSAutoreleasePool to handle autoreleased objects.
The fact that you are autoreleasing objects does not, in itself, prevent a memory leak. Since you're not seeing messages in Console telling your that your objects are being autoreleased outside a pool, it indicates that the problem isn't that they're not being put into a pool.
You must not be managing your retain count properly. Remember that all calls to -alloc and -copy must be balanced by calls to -release or -autorelease. Perhaps you aren't releasing your member variables in a class's dealloc method somewhere. Start by using Instruments to find where you are allocating / copying your objects, then look at every place you retain and release them to ensure each object's retain count is balanced.
From the WWDC videos standard practice holds that a tight loop with a lot of variables flying around is a good place to put one. Start it before the loop, everything in the loop that is autoreleased should go to that pool, and drain it afterward.
If I have an object created as autoreleased, is there a way that I can mark it is essentially "not autoreleased"?
I feel that I have heard calling [object retain] will do what I am looking for but I am not sure.
Depending on what you really want [object retain] will do it...or nothing will.
If what you want is "my object should live past the drain of the autorelease pool", then [object retain] will do that for you. It will make the object live until you have a matching number of [object releases]s (or [object autorelease]s + pool drains).
If you want the object to not make the autorelease pool bigger, not to make the pool drain fractionally slower, or to make sure to object dies BEFORE the next pool drain, then [object retain] will not do it. In fact the only real way to do any of those things is to make sure the object never goes into the autorelease pool (or to a lesser extent, make a private autorelease pool and manage its lifecycle).
When an object is sent autorelease, it adds itself to the autorelease pool. At each iteration of the run loop, the autorelease pool is drained. It drains itself by sending it a release message to every object in the pool. If an object is added to the pool twice, it is sent two release messages, and so on. It is a very simple mechanic that greatly simplifies memory management.
If you have an object that has already been sent an autorelease message, then by sending that same object retain, you are cancelling out the effect of what will happen when the autorelease pool is drained.
Yes, calling [object retain] is exactly what you want.
I have a NSDictionary that is passed from the main thread to a second thread which retains, uses, then releases the variable.
What if the main thread autorelease pool is drained while the 2nd thread is still using the variable? Even though I have retained the variable in the 2nd thread, will the main thread's pool know that its still being used?
Thanks.
The autorelease pool is pretty dumb. It doesn't "know" that any variable is being used. It simply calls release on each autoreleased object. This generally occurs at the end of each iteration of the event loop.
If the autorelease pool is drained before your second thread has a chance to retain it, it will be deallocated. Instead, it's generally a good idea to retain anything that will be used in another thread before starting the thread. You have no way of knowing when the thread will run, so it's best to assume it won't run until after the autorelease pool is drained.
In other words, do something like this:
NSDictionary *dictionary = // Get the autoreleased dictionary... somehow
[NSThread detachNewThreadSelector:#selector(myThread:) toTarget:self withObject:[dictionary retain]];
Bear in mind your thread now owns dictionary and is responsible for calling release on it before the thread exits, or else your app will leak memory.
I am wondering if the autorelease pool holds strong or weak references to the objects it holds. I would guess they are weak. When I add an object to an autorelease pool, it's just not immediately released but will be released when the pool is drained, right? So the references should be weak, i.e. the reference count (or retain count) keeps the same when I add an object to an autorelease pool?
Talking of strong versus weak references makes sense in the context of a garbage collected memory management environment (where weak pointers are automatically released and cleared even if referenced). With GC enabled, all retain/release/autorelease calls are essentially do nothing operations (though the NSAutoreleasePool -drain method triggers garbage collection).
Now since you've tagged this question as iPhone related, and there's no garbage collection on iPhone, I'm assuming you're referring to regular reference counting, by strong you mean increasing the retain count of the referenced object, and by weak you mean just storing the pointer value.
The autorelease method essentially moves ownership of an object from the calling code to the current autorelease pool, you can think of the calling code calling release and the pool calling retain.
So the reference is effectively strong, but your code loses ownership and release responsibility. Object release will be called when the autorelease pool is released/drained.
The whole point of the autorelease pool is that it is a deferred release. For example, you can call autorelease on a local object you will be returning in a method so that it gets released even though you lose the reference to the object when the method returns.
Yes. retain count keeps the same, and yo can can check, that it is so:
id obj = [[NSObject alloc]init];
NSLog([NSString stringWithFormat: #"%d", [obj retainCount]]);
[obj autorelease];
NSLog([NSString stringWithFormat: #"%d", [obj retainCount]]);
The retain count remains the same, basically firing an autorelease message on an object makes the developer free from having the ownership and release responsibility.
This is how autorelease pool works-
Every time an instance of autorelease pool is created, it's added on top of the stack, so the most recent autorelease pool will be used by the system. And whenever you add any object in the autorelease pool, it's added on the top autorelease pool in the stack. An autorelease pool is basically an array on which the autoreleased objects are added. Every object added in autorelease pool is released when that particular autorelease pool is released(/drained). An autorelease pool is created first before the system starts processing any event, and it remains there till the current event loop's execution is over. When system see's that current event loop is completed then it get's the topmost autorelease pool associated with that event loop and releases it. Releasing an autorelease pool/ draining means getting each object added in autorelease pool and firing a release message on object, till all the objects in autorelease pool are released.
In the docs there is an addObject: method of NSAutoreleasePool.
I thought about this:
NSString *myString = [[NSString alloc] initWithCString:"Does this work?"];
[thePool addObject:myString];
[anotherPool addObject:myString];
Is that possible? I always read that I can only add objects to the topmost one on the autorelease pool stack.
Yes, you can. But you never should. There is categorically no reason to do this.
What you are doing is possible, but may cause an exception at run time because myString will be sent a -release message after deallocation (assuming the last remaining reference is by the first pool). In general, as the -[NSAutoreleasePool addObject:] documentation states, you should not add an object to an autorelease pool manually but rather by calling -autorelease on that object. This will put the object in the active autorelease pool for the current thread (each thread has its own autorelease pool).
I am a little bit confused now because of this from Apple:
When an object is autoreleased—that
is, when an object is sent an
autorelease message or when it is
passed as the argument to the
addObject: class method—it is always
put in the autorelease pool at the top
of the stack.
On the other side, they don't mention it in the NSAutoreleasePool Class Reference. So I guess even when I cal addObject: on a specific one, then it will go onto the one on top of the Autorelease Pool Stack. Actually I'll have to try it out ;)