i got an message at my log file (GDB) as object is leaking...
NsAutorelease pool.. like something nearly for 10 times.
Can anyone explain me. why this message is displaying..?
Thanks in advance.
It means you are autoreleasing objects with no autorelease pool in place. So those objects are not being released, and are probably leaking as a result.
So you should make sure you have a pool in place.
I generally use:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Your autoreleased objects
[pool release];
But it depends on where in your code you're running in to the issue... Are you using multi-threading? Or is everything happening in the main thread?
Related
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.
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
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.
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
I am using this line of code in iphone 2.0 its work fine
pool=[[NSAutoreleasePool alloc]init];
[pool release];
When i run this line of code in iphone 3.0 its give some leak message in the log screen..
That message is
2009-10-13 03:26:31.841 Spectrum[3946:4c2b] *** _NSAutoreleaseNoPool(): Object 0xd819d0 of class NSCFString autoreleased with no pool in place - just leaking
Stack: (0x305a2e6f 0x30504682 0x52c14d 0x536f67 0x3058deff 0xb049 0xa554 0x3050a79d 0x3050a338 0x97181155 0x97181012)
can anyone help me?
Thanks in advance....
Your pool allocation and release code looks fine. The error message, nevertheless, indicates something was allocated with autorelease outside the scope of an autorelease pool. This often happens in when you use a secondary thread, when using some specialty load methods, and when initializing globals.
Once you isolate the leaking bit of code, you could try wrapping it by another set of NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; and [pool release];.
That message occurs when an object is sent the autorelease message outside of an autorelease scope. Place a breakpoint on _NSAutoreleaseNoPool and check the stack to see where the pool needs to be added.
Look for any place in your code where you make autoreleased objects, while inside another thread than your main run loop.