views:

598

answers:

3

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];
    }
}
A: 

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.

TechZen
A: 

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.

Marcus S. Zarra
I just updated my post to include some code in case it helps. Thanks.
toofah
Thanks for your help. I used an iVar so that I could find the pool easily in order to drain and re-create it from an external class. The property is an 'assign' property.
toofah
The last 2 calls immediately before the drain call are save and reset on the NSManagedObjectContext.
toofah
+2  A: 

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

It seems like this is a warning that isn't really problematic. I don't see any ill effects, just hate to fill up my log file with this kind of junk.
toofah