NSAutoreleasePool carrying across methods? - iphone

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/

Related

When is manual memory management necessary on the iPhone?

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

Is an autorelease pool necessary if I'm not creating autoreleased objects?

I mean, if I were absolutely certain I wasn't creating any autoreleased objects, then of course it wouldn't. My real concern is if there's anything else under the hood I don't understand. I have a background thread that calls a function. Must I always create an autorelease pool anyway?
- (void)someFuncOnABackgroundThread
{
//don't seem to need this. no leaks found
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//do something that doesn't create any objects, or only use alloc/init/release
NSString* str = [[NSString alloc] init];
[str release];
[pool drain];
}
Yep! You have to. You might be calling a function that's internally using autorelease pools, so you never really know if you're using or not any autorelease.
Good luck!
ultimately, it depends on the interfaces you're using in the implementation.
example 1
if you're interacting with Foundation or other objc types, you should. without question.
to answer specific to the example you've posted: definitely create one in this case -- NSString apis should assume an autorelease pool is in place.
example 2
if you're dealing entirely with apis in libc, there is no need.
bottom line
it can take a lot of time to understand where it's necessary (or not).
implementations can change, and they could introduce autoreleased objects.
you should guarantee a leak is never introduced, especially for such a simple reason.
it's a simple problem to overcome: if in doubt, create one.

How often should I put NSAutoreleasePools in place?

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.

Attempt to pop an unknown autorelease pool

Does anyone know what this error means?
*** attempt to pop an unknown autorelease pool
I am seeing this in my app that uses NSOperations in NSOperationQueue. Each operation has it's own Autorelease pool. Since each operation is parsing xml and pushing information into Core Data, I periodically 'drain' my autorelease pool and re-create it. If I don't drain the pool, I don't see these errors.
UPDATE:
Here's my code:
In the main of my NSOperation, I alloc the pool and assign it to an 'assign' property like this:
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
at the end of my main I release it like this:
[self.downloadAndParsePool release];
self.downloadAndParsePool = nil;
If the operation does a lot of parsing and inserting into Core Data, it will call my drain method periodically:
- (void) drainAutoreleasePool
{
// drain and re-create autorelease pool...this method is called periodically to keep memory down during parsing of large trees
if (self.downloadAndParsePool)
{
[self.downloadAndParsePool drain];
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
}
}
It seems that the issue is caused by the fact that the drain is called outside of the method that allocated the pool even if on the same thread. Here is what NSAutoreleasePool Class Reference says.
You should always drain an autorelease
pool in the same context (invocation
of a method or function, or body of a
loop) that it was created.
The message you see is triggered by your call to drain in drainAutoreleasePool:
[self.downloadAndParsePool drain];
NOTE: XMLPerformance sample app uses the same pattern of periodically draining the pool. It also produces this message since iOS4.0
How To Actually Fix This
The accepted answer here is correct, but here are some more details on how to fix it because it's not a good idea to just live with issues that are filling up your console. A log statement is being printed and there is a reason for it. Something is awry.
Turns out this code is from Apple's own example project called XMLPerformance, found here: http://developer.apple.com/library/ios/#samplecode/XMLPerformance/Introduction/Intro.html
In the source file, LibXMLParser.m, simply change this line:
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
to this:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
at the beginning of the - (void)downloadAndParse:(NSURL *)url method and then change:
[downloadAndParsePool release];
self.downloadAndParsePool = nil;
to this:
[pool release], pool = nil;
at the end of that method. Now remove the ivar called downloadAndParsePool. Once you've done all of that, the messages will go away.
Magically delicious.
It sounds like you've lost a pool somewhere. Pools are objects and its possible for them to be over released. They also stack in a fashion. IIRC, when you have nested pools, draining an outer pool automatically drains the inner pools. I think you've got a pool object that dies without being drained. When the outer pool tries to drain it, it never gets a response.
Just a guess.
It would be very helpful if you could show the code that does the creation of the pool, the drain of the pool and the re-creation of it. Otherwise we are just guessing at answers.
update
First, pools like that should be a local variable inside of the -main instead of an iVar like that. Second, how is your property defined? Is it an assign or a retain?
Update2
I would still recommend against using an iVar to store that pool. Nevertheless since it is an assign that should be fine.
When you drain the pool, are you also saving and resetting the NSManagedObjectContext associated with that operation? NSManagedObjectContext makes very heavy use of the autorelease pool and if you are not resetting it at the same time as the drain that could be causing an error.
Update3
Ok, then we are left with TechZen's suggestion that you are losing a pool somewhere. I would put log statements in after you create a pool and spit out its pointer address and put a log statement in just before the drain that also spits out the pointer address. Then match them up. If they match up then the leak is somewhere else.
If you create a pool with NSAutoReleasePool
So that it automatically releases
there is no need for release in dealloc
The app sometimes crashes if you use NSAutoReleasePool
and also release the pool in dealloc

Autorelease: Use always when you've NARC'ed?

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.