Attempt to pop an unknown autorelease pool - iphone

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

Related

How to handle leaks when using a multiple threads in iphone?

I have called a method in separate thread in viewdidload method
[NSThread detachNewThreadSelector:#selector(callWebService) toTarget:self withObject:nil];
-(void)callWebService{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSThread detachNewThreadSelector:#selector(loadImages) toTarget:self withObject:nil];
[pool release];
}
-(void)loadImages{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self performSelectorOnMainThread:#selector(reloadTable) withObject:nil waitUntilDone:false];
[pool release];
}
-(void)reloadTable
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[myTableView reloadData];
[pool release];
}
How to handle leaks while using thread? I want to use threads.
Errors
*** __NSAutoreleaseNoPool(): Object 0x604b830 of class NSCFString autoreleased with no pool in place - just leaking
*** -[NSAutoreleasePool release]: This pool has already been drained, do not release it (double release).
The autorelease pool must be drain, not release. So I think if you change it to [pool drain] it should be working fine.
Don't know if you found your answer yet, but as I had hit something similar to your problem, I did some looking. It seems that when you drain a pool, that is (effectively) equivalent to releasing it. The documentation on the class says:
Since you cannot retain an autorelease pool (or autorelease it—see
retain and autorelease), draining a pool ultimately has the effect of
deallocating it.
So, you should only drain a pool once. If you need another context after that point, you should generate a new pool in the same way you generated one earlier in your code.
If there is no pool available, then you can end up leaking (as you mentioned). However, autorelease calls should log a warning message in that instance. Regarding threads, the documentation has this to say
The Application Kit creates an autorelease pool on the main thread at
the beginning of every cycle of the event loop, and drains it at the
end, thereby releasing any autoreleased objects generated while
processing an event. If you use the Application Kit, you therefore
typically don’t have to create your own pools. If your application
creates a lot of temporary autoreleased objects within the event loop,
however, it may be beneficial to create “local” autorelease pools to
help to minimize the peak memory footprint.
Hope this helps.

__NSAutoreleaseNoPool(): Object 0x753c2f0 of class General autoreleased with no pool in place - just leaking

I haven't noticed my console output for a while and I've suddenly noticed lots of weird errors.
__NSAutoreleaseNoPool(): Object 0x753c2f0 of class General autoreleased with no pool in place - just leaking
__NSAutoreleaseNoPool(): Object 0x753c300 of class __NSArrayM autoreleased with no pool in place - just leaking
I've no idea where this happening?
Edit..
I use this
[self performSelectorInBackground:#selector(startupStuff) withObject:sender];
With statupStuff I have this
General *rdb = [[General alloc] autorelease];
[rdb refreshDBData];
The Errors happen shortly after code in the refreshDBData method.
Autorelease pools are tied to threads. If you create a thread through performSelectorInBackground then you need to create and destroy an autorelease pool for yourself. So you need startupStuff to look like this:
- (void)startupStuff:(id)sender
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// ... everything else you were doing ...
[pool drain]; //see comment below
}
Addition: Richard below makes the point that drain is preferable to release to acknowledge that (on the desktop, not yet on iOS) you may be running with a garbage collector. Apple's specific words are (source):
In a garbage-collected environment, sending a drain message to a pool triggers garbage collection if necessary; release, however, is a no-op. In a reference-counted environment, drain has the same effect as release. Typically, therefore, you should use drain instead of release.
So I've corrected my example. Suffice to say, this specific question is to do with the iPhone and currently there is no garbage collection on that device. So the originating poster is in the "drain has the same effect as release" camp, not the "drain ... triggers garbage collection if necessary; release, however, is a no-op" camp.
This:
General *rdb = [[General alloc] autorelease];
Is wrong. There should always be a call to an initializer; to -init, at the least.
Try this
[self performSelectorInBackground:#selector(startupStuff) withObject:sender];
-(void)startupStuff:(id)sender
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
General *rdb = [[General alloc] init];
[rdb refreshDBData];
[rdb release];
[pool release];
}
If its not working too then you need to check refreshDBData method.. you are doing something wrong there

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.

Class Methods Used Many Times Cause Leaks?

Let's say I'm developing a game. I run the following class method thousands of times:
NSBundle *bundle=[NSBundle mainBundle];
I do not create an autorelease pool and release the objects that call the above class method all the time. I create an object, it calls the above class method, I release it, and on, and on, thousands of times.
3 questions:
Is memory leaked?
If I ran:
NSAutoReleasePool *pool=[[NSAutoReleasePool alloc] init];
[pool drain];
would it then effectively release all those NSBundles created in the class method?
if I wrote:
pool=nil;
instead of writing:
[pool drain];
Would the same effect be achieved? Is this good practice?
The three questions are correlated and I will boost the one that clarifies them :)
No, memory is not leaked. [NSBundle mainBundle] returns an autoreleased object, so the autorelease pool will take care of it. However, if you're going to call it a bunch of times in one function or something, you'd be better off either getting a reference to it once and just holding on to it while you need it, or creating your own autorelease pool.
Not exactly. Everything after NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; that is autoreleased will go into pool, and after you drain the pool, they'll be released. Note: [pool drain]; also releases the pool, so don't call [pool drain]; [pool release]; or you will send the release message to the object twice and probably crash.
No. pool = nil; would just lose the reference to pool and the actual pool object would be leaked. You have to call either [pool drain]; or [pool release]; and good practice would be to set pool = nil; afterwards.
If you do not create an autorelease pool, and one does not already exist, any objects that are autoreleased (either by you, or by other libraries you are using) will be leaked.
setting pool=nil; does nothing except leak the whole pool, perhaps if the pool was set in a property i.e.
#property(nonatomic, retain) NSAutoreleasePool *pool;
self.pool = [[[NSAutoreleasePool alloc] init] autorelease];
//now, self is the sole retainer of pool, so if self abandons it it gets drained:
self.pool = nil;
//pool's retain count drops to zero, pool drains.
If you are doing this thousands of times, it might slow things down to drain the pool every time, consider doing it every 5 or ten times, set a counter in the loop and when it hits some decided number, do this:
self.pool = [[[NSAutoreleasePool alloc] init] autorelease];
//this will get rid of the old pool and put in a new one, so you only have to get rid of the one remaining at the end of the loop.

NSAutoreleasePool carrying across methods?

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/