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.
Related
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"
Sometimes I see developers use:
ClassA *obj = [[ClassA alloc]...]autorelease];
Why does this sometimes autorelease the objects and sometimes not?
Or is this an error?
Autorelease just means "this will be released at a later date". If you autorelease something three times, it will be released three times, later.
Instead of guessing, read through and understand the Memory Management Programming Guide before you do anything else. It will save you a ton of time and frustration.
You also asked, in the comments to another answer, why people use autorelease to begin with. Autorelease is necessary for a common case where you have to create a new object and return it. By the other rules of memory management, you would need to release the object at some point or it would be leaked, but if you release it before you return it, it will go away immediately.
There are two ways that you could deal with this: a) to have these methods return a new object which the caller is expected to release when it is done with the object, and b) to make sure that the object is released as soon as the caller is done with it.
The way Cocoa and Cocoa Touch handle this situation by convention is option b): to use autorelease pools, because you won't have to keep track of ownership except for the objects you explicitly create. Some people use autorelease for nearly everything instead of release, and this is a bit more inefficient than release, but more importantly it hides any useful distinctions you might make between release and autorelease when you're trying to read, navigate and understand the code.
As I said earlier, please read the Memory Management Programming Guide and all these questions will be answered. Better yet, if you just follow the simple rules listed in there, you won't have to think deep thoughts about every combination; there'll be a general rule to follow for your situation and the rule will work.
There's no error with autorelease - it just sets the object to be automatically released at a later time, which you don't necessarily have control over.
I try to always explicitly release my objects, unless I don't have a choice such as when returning a newly alloced/init-ed object from a method.
Actually when you create an object by using the following statement,
ClassA *obj = [[ClassA alloc]init ...];
Then you need to release that object, other wise it will be remain in that app and not useful by any other objects. Then the memory will be wasted.
So we have to release the object by [obj release];
in case some time we can't release at specific time. So we will put autorelease. If we do like that then the NSAutoReleasePool handle the release operation.
We can use any of the above.
Reagrds,
Satya.
No, it's not an error at all. Autorelease means that the object will be released at the end of the current Autorelease pool.
Look at your main.m class file (Every Cocoa/Cocoa Touch project gets it). You will see it has a method that looks a bit like this:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
UIApplicationMain(.....);
[pool release];
UIApplicationMain starts your app's run loop. When you reach the end of it, (The application is closed) anything in the autorelease pool is dumped.
Now, if you impliement multithreading and you create your own Autorelease pools within the pool, you'll release the object when that pool is released.
The documentation on the method is here: http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/autorelease
I know this question looks like a dupe: I checked and it's not
In talking about NARC, the author of this blog says, "Personally, I like to immediately autorelease anything I NARC-ed, on the same line." This goes completely counter to all the examples I've seen on the Apple site and in books, where autorelease is only used when the object must be returned and cannot be released immediately. In general, the idea is that autorelease is memory intensive and can gum up your program (though it makes code cleaner). From Appress Beginning iPhone 3 Development:
these objects can have a detrimental
effect on your application’s memory
footprint. It is OK to use
autorelease, but try to use it only
when you really need to, not just to
save typing a line or two of code.
I am not asking if autorelease is worse than explicitly calling release (it is), but rather:
In most 'normal' situations on iPhone, just how bad is it to replace a later release with an earlier autorelease (in the same method)? Also, in what situations would it be absolutely prohibitive to do this?
My guess is that, compared to using a garbage collector (as MonoTouch apps do sucessfully), autorelease will hardly make a dent in your memory footprint, and that Vincent's advice it right on, and can make for cleaner code and less accidental memory-leaks.
There's nothing wrong with using autorelease, but when you allocate objects in a loop, you should always call release explicitly.
Using autorelease:
for (int i=0;i<1000;i++) {
NSString *s = [[[NSString alloc] init] autorelease];
}
// at this point, there are 1,000 unreleased string objects in memory
Using release:
for (int i=0;i<1000;i++) {
NSString *s = [[NSString alloc] init];
[s release];
}
// at this point, no string objects are "alive"
As you can see, you have to be really careful when using autorelease in loops.
You should be aware how autorelease works. Each thread in your application normally has a single autorelease pool. Objects can be registered in the pool. At the time they are registered, the pool determines the stackframe they belong to and will automatically pop the from the pool whenever that stackframe is left.
While this may seem costly (and it certainly is compared to direct retain/release), I don't think it even close to the cost a generation mark and sweep garbage collector can have.
Where autorelease really shines is in all situations where exceptions may be raised and there's no try/catch around. Autorelease is definitely preferable to a direct release in such cases.
There are, however, situations where you should avoid autorelease (the same goes for garabge collected environments where you should try to avoid these situations too). Creating temporary, autoreleased objects in a loop which runs a huge number of times is such a scenario, which puts significant stress on a garbage collector or the autorelease pool.
Replacing release with autorelease should be avoided in worker threads that are very simple and can live without the overhead of an autorelease pool. So the guideline is: Whenever you can avoid it, you should, whenever you're unsure autorelease.
From reading the memory management docs in the SDK, I gathered that factory methods (static constructor methods) would typically be retaining the object for me and adding it to the autorelease pool?
This would mean I have no need to retain & release an object as long as the pool does not get released before I expect? (Which should be at the end of the app, for the default autorelease pool in main()? )
This question: Cocoa Touch Question. Should [NSMutableArray array] be retained? seems to agree with this.
However when I have used the NSMutableArray arrayWithCapacity: method, I've found I have to retain the array or all heck breaks loose.
I'm sure this is all just total n00b-ness, or a bizarre bug elsewhere in the code, but if someone could explain how exactly I may have misunderstood, I'd be much obliged.
Thanks!
Update: Thanks for the answers. I think I've got it now!
From reading the memory management docs in the SDK, I gathered that factory methods (static constructor methods) would typically be retaining the object for me and adding it to the autorelease pool?
Yes, you don't have to worry about releasing objects returned from any method, except the alloc, init, new, and copy methods.
This would mean I have no need to retain & release an object as long as the pool does not get released before I expect?
Yes.
(Which should be at the end of the app, for the default autorelease pool in main()? )
No. You can only count on the object being around until you return from whichever method or function you're in. Typically, autorelease pools are flushed when control returns back to your run loop.
If you want an object instance to survive beyond the current method you must take ownership of it, by calling 'retain'. You are then also responsible for 'releasing' the instance when you no longer need it.
In your case, if you want your NSMutableArray to stick around, you need to retain it. Better yet, use [[NSMutableArray alloc] initWithCapacity: ];
See Practical Memory Management
Usually auto-release pools are drained at the end of the current event loop. A pretty good rule of thumb is that unless you're returning an autoreleased object, if you want that object to remain outside of the current method, you should retain it.
So, when you create your NSMutableArray as an autoreleased object, once your method ends, all bets are off, and that autorelease pool could drain at any time. Retain it, and then release it in your dealloc.
Checkout this diagram below explaining the Application lifecycle. Once the application has launched, your application will be handling various events which could be user generated such as a touch, or a network activity, or one of many events. Once the event has been handled, control returns to the Event Loop that you see below.
This event loop maintains the top level autorelease pool. In pseudocode, this event loop would look something like:
while(wait for event) {
1) create autorelease pool
2) handle event
3) release pool
}
So, whenever a event has been handled, control goes back to the main event loop, and this outer pool will be released. You should retain all objects that were created using convenience methods and will be needed even after the event handling finishes. With the extra retain count, you take ownership of the object and are responsible for releasing it when no longer needed.
iPhone Application http://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Art/app_life_cycle.jpg
As soon as you add your object to the array, there is an implicit call to retain for this object, which means once added to the array you can release it from the source, and when you'll call the remove method from the array there will also be an implicit call to release.
I'm building an iPhone application where I detach some threads to do long-running work in the background so as not to hang the UI. I understand that threads need NSAutoreleasePool instances for memory management. What I'm not sure about is if the threaded method calls another method - does that method also need an NSAutoreleasePool?
Example code:
- (void)primaryMethod {
[self performSelectorInBackground:#selector(threadedMethod) withObject:nil];
}
- (void)threadedMethod {
NSAutoreleasePool *aPool = [[NSAutoreleasePool alloc] init];
// Some code here
[self anotherMethod];
// Maybe more code here
[aPool drain];
}
- (void)anotherMethod {
// More code here
}
The reason I ask is I'm receiving errors that objects are being autoreleased with no pool in place, and are "just leaking."
I've seen other questions where people didn't have autorelease pools in place at all, and I understand why an autorelease pool is needed. I'm specifically interested in finding out whether an autorelease pool created in (in this example) threadedMethod applies to objects created in anotherMethod.
To answer your question, yes, anotherMethod is using the NSAutoreleasePool you created in threadedMethod, and anything you autorelease there will be released when aPool is released/drained.
So it is unlikely that your error is stemming directly from this code (unless there is more going on).
Put a break point on _NSAutoreleaseNoPool (add it by name in the Breakpoints window) and run your code in the debugger and it will stop when autorelease is called without a pool and that should resolve your problem.
In your example, yes, NSAutoreleasePool is carrying across methods since the invocation of [self anotherMethod] is nested inside -(void)threadedMethod.
Q: NSAutoreleasePool carrying across methods?
A: It depends:
Across nested invocations, yes.
Across sibling invocations, no.
And no matter what, the NSAutoreleasePool instance itself goes out of scope when the parent scope goes away. -in your example, at the very end of -(void)threadedMethod { }.
The article mentioned earlier (http://thegothicparty.com/dev/macos/nsautoreleasepool/) is quite clear about that.
The autorelease pool does carry through to anotherMethod. However, when your threaded function ends, you should call [aPool release] instead of [aPool drain]. They are roughly equivalent, but aPool release causes the NSAutoreleasePool to release itself in addition to all the other objects in the pool. When your threaded function ends after calling drain, the autorelease pool still has a retain count of +1! Odds are, the "just leaking" object is aPool!
EDIT:
Jim Puls is right about release and drain being equivalent. The Apple docs clearly say they are identical in the non-garbage collected environment, and drain is better in the garbage collected case. My fault for not reading the docs!
Here's an article that presents a general overview of NSAutoreleasePools - it should help point you in the right direction. Since there is a virtual stack of autorelease pools, the topmost one will be used everywhere within your app - regardless of where objects are being autoreleased.
http://thegothicparty.com/dev/macos/nsautoreleasepool/