I do this:
NSString *fullpath = [[NSBundle mainBundle] pathForResource:#"text_file" ofType:#"txt"];
Why the following message appear?
Is my code leaking?
2010-03-31 13:44:18.649 MJIPhone[2175:207] *** _NSAutoreleaseNoPool(): Object 0x3909ba0 of class NSPathStore2 autoreleased with no pool in place - just leaking
Stack: (0x1656bf 0xc80d0 0xcf2ad 0xcee0e 0xd3327 0x2482 0x2426)
2010-03-31 13:44:18.653 MJIPhone[2175:207] *** _NSAutoreleaseNoPool(): Object 0x390b0b0 of class NSPathStore2 autoreleased with no pool in place - just leaking
Stack: (0x1656bf 0xc80d0 0xc7159 0xd0c6f 0xd3421 0x2482 0x2426)
2010-03-31 13:44:18.672 MJIPhone[2175:207] *** _NSAutoreleaseNoPool(): Object 0x390d140 of class NSCFString autoreleased with no pool in place - just leaking
Stack: (0x1656bf 0xc6e62 0xcec1b 0xd4386 0x24ac 0x2426)
This happens because you are running in a thread. User threads don't share the main threads autorelease pool, so you need to create your own. Otherwise, objects like these will never get released, thus leaking.
In the beginning of your thread method, before the loop or whatever, do:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Before returning, release it:
[pool drain];
At the time you run that line of code, no NSAutoreleasePool has been created on the current thread.
If you're running on the main thread, Cocoa (and Cocoa Touch) automatically provides an autorelease pool for you. If you've scheduled something to happen on a separate thread (which would also include something scheduled by performSelectorInBackground:withObject:), then you need to provide your own autorelease pool.
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.
Would it shed more light if I told that fetchHTML was being called in a seperate thread? I am also seeing several messages in the debug console such as:
_NSAutoreleaseNoPool(): Object 0xd92860 of class NSCFDictionary autoreleased with no pool in place - just leaking
_NSAutoreleaseNoPool(): Object 0xd92800 of class NSCFString autoreleased with no pool in place - just leaking
I am new to iPhone app development, Objective-C but not new to programming or C/C++. I am using the leaks performance tool and it shows many leaks. This is a 10.5 kb leak and it occurs on the line:
NSString * xml = [NSString stringWithContentsOfURL:urlobj];
The stack trace on this below is:
stringWithContentsOfURL
initWithContentsOfURL
initWithDataOfEncoding
...
Does anyone have an idea why this must be happening. I am under the impression that I get an autorelease object here and I can return this to the caller without calling retain. I am not using the xml object to store in an instance variable, just for processing.
Here is the function code:
- (NSString *) fetchHTML: (NSString* ) url{
#try
{
NSURL* urlobj = [NSURL URLWithString:url];
NSString * xml = [NSString stringWithContentsOfURL:urlobj];
return xml;
}
#catch( NSException *ex){
NSLog(#"Error fetchingHTML");
return nil;
}
return nil;
}
Yup; that shouldn't be leaking.
It might be a false positive in that the URL subsystem is caching the contents of the URL and doing so in a way where the pointer is no longer visible to leaks analysis.
If you can, retry the test on Snow Leopard. Leaks detection on Snow Leopard is significantly faster and more accurate.
I completely agree with you that this should not cause a leak. I've been coding in Cocoa/Objective-C for 2 years now, and that looks like it should work.
That being said, I notice that Apple's documentation indicates that the stringWithContentsOfURL: method is being deprecated. Perhaps it would work as follows:
NSString * xml = [[NSString alloc]
initWithContentsOfURL:urlobj
encoding:NSASCIIStringEncoding
error:nil];
return [xml autorelease];
As the error message says, there's no autorelease pool for the string to go into, and that creates a leak. NSAutoreleasePools exist on a per-thread basis. Cocoa creates one in the main event loop of the main thread, but that's the only one it creates for you. If you're somewhere other than the main thread and you're going to be dealing with autoreleased objects, you need to create an autorelease pool for that thread as well.
You can check out the NSAutoreleasePool docs for more information on how autorelease pool stacks work.
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.