I was reading the Memory Management Guide for IPhone OS and I didn' t understand a point in the Autorelease Pools section Listing - 1 code example:
void main()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *args = [[NSProcessInfo processInfo] arguments];
for (NSString *fileName in args) {
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
NSError *error = nil;
NSString *fileContents = [NSString stringWithContentsOfFile:fileName
encoding:NSUTF8StringEncoding error:&error];
/* Process the string, creating and autoreleasing more objects. */
[loopPool release];
}
/* Do whatever cleanup is needed. */
[pool drain];
exit (EXIT_SUCCESS);
}
It says that :
".......Additionally, any autoreleased objects created in the context of the for loop (such as fileName) are released when loopPool is released even if they’re not explicitly sent an autorelease message."
The point that I didn't understand is how the fileName variable is included in the second pool(loopPool) but not the first one(pool). Isn't the fileName created when the first pool is the top most pool in the pool stack ?
You are right. fineName is in the outer pool. If it's like this in the docs, it's a bug.
Edit: Feel free to file a bug report at Apple's radar system.
Related
In my code i am working with audio buffers, when i have a callback function that is being called many times per second. this callback is in a class that handle audio, and not in the main class of the app .
At the start i was getting this warning that is being log many times during callbacks:
Object 0x93cd5e0 of class __NSCFNumber autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool()
Then i was told to put this line in the callback func :
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
then this error disappeared .
But i cant understand how is that possible that i alloc the pool so many times in 1 second- and maybe i have a memory issues.
I saw than that i have to put this at the end :
[pool drain];
so i have this :
OSStatus status;
status = AudioUnitRender(audioUnit,
ioActionFlags,
inTimeStamp,
inBusNumber,
inNumberFrames,
&bufferList);
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // that line added
//run on evert sample
int16_t *q = (int16_t *)(&bufferList)->mBuffers[0].mData;
for(int i=0; i < inNumberFrames; i++)
{
static int stateMachineSelector=1;
static int sampelsCounter=0;
// CODE TO HANDLE THE SAMPLES ...
}
[pool drain]; // issue here
what exactly i did here?
why is that ?
is that ok from memory aspect ?
thanks a lot .
When starting a Autorelease pool with [[NSAutoreleasePool alloc] init] all further objects receiving a autorelease or where created with the convenience allocator (like NSArray *ary = [NSArray array];, or UIView *view = [[[UIView alloc] init] autorelease]; are in that pool.
So:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *ary = [NSArray array];
[pool release]; // this will also release and dealoc the *ary from memory
If you have a callback running NOT no the main thread, you SHOULD do a new pool. If not, your objects may leek to nirvana. :)
If you process a lot of data with autorelease objects and you'd like to free the memory, then create a pool, process, release the pool.
In Xcode 4.2, does #autoreleasepool replace [pool drain]; and do I still need to allocate like so:
Person *Jay = [[Person alloc] init];
This # autoreleasepool { } is equivalent to
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Code benefitting from a local autorelease pool.
[pool release];
ARC still requires you to do either
[[NSString alloc] init]
or
[NSString string]
Under ARC there is no difference from the casual programmer perspective. Underneath, in the compiled code, the object returned by [NSString string] will go into a pool and later be released. The inited one will have a release inserted by the compiler just before it goes out of scope.
If you are not using ARC then you will later have to call release on the object returned by string.
Hey experts, I'm having a little trouble with NSThread. Xcode keeps on giving me "* __NSAutoreleaseNoPool(): Object 0x5694dc0 of class NSCFString autoreleased with no pool in place - just leaking" errors.
I'm correctly declaring the pool with the line
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
then at the end of my loop I use:
[pool release];
Is it because I'm using a delegate method as the performSelectorInBackground?
Thanks stackoverflow.
- (void)preFetch { //process filenames to be downloaded and assign types to each one
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *regions = [NSArray arrayWithObjects: #"dr_national", #"ds_ir", #"conus_FL360", #"FL360_conus", #"dr_nw", #"dr_nc", #"dr_ne", #"dr_sw", #"dr_sc", #"dr_se", #"ds_ir_nw", #"ds_ir_nc", #"ds_ir_ne", #"ds_ir_sw", #"ds_ir_sc", #"ds_ir_se", nil];
NSError* error;
for (NSString *regionDir in regions) {
NSLog(#"region now: %#", regionDir); foo = 0;
NSString *regUrl = [NSString stringWithFormat:#"http://someUrl/%#/index.lst", regionDir ];
NSString* text1 = [NSString stringWithContentsOfURL:[NSURL URLWithString:regUrl ] encoding:NSASCIIStringEncoding error:&error];
NSArray *listItems = [text1 componentsSeparatedByString:#"\n"];
for (int k=0; k<[listItems count]; k++) {
if ([[listItems objectAtIndex:k] length] != 0){
NSString *newpath = [NSString stringWithFormat:#"http://someUrl/%#", [listItems objectAtIndex:k]];
NSLog(#"newpath: %#",newpath);
[self performSelectorInBackground:#selector(moveProgressBar) withObject:nil];
[self fetchImages:newpath:type]; //pass multiple arguments to fetchImages, newpath and type
}
}
}
[pool release];
}
- (void)moveProgressBar{
[delegate increaseAmount];
}
You should just set up an autorelease pool in your method, since that's being called on a different thread.
- (void)moveProgressBar
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[delegate increaseAmount];
[pool drain];
}
Edit
Having said that, looking at the code itself, it seems that you might be trying to update the UI from a background thread? Any code that does that should be executed on the main thread.
If you have a long running process that you want to run which doesn't lock the UI, and keeps the user updated on progress, the typical pattern would be to do the processing itself on a background thread, and periodically update the UI using performSelectorOnMainThread:.
I have noted several other threads on this topic and have tried wrapping my threaded code with:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[pool release];
but the errors still come.
I am using a static method to instantiate a dictionary of words.
Here is some code:
-(id)init
[NSThread detachNewThreadSelector:#selector(loadDictionary:) toTarget:[IntroScreen class] withObject:nil];
[NSThread setThreadPriority:1.0];
return self;
}
+(void)loadDictionary:(id)param
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[[SimpleAudioEngine sharedEngine] preloadEffect:#"click.wav"];
[[SimpleAudioEngine sharedEngine] preloadEffect:#"pop.wav"];
[[SimpleAudioEngine sharedEngine] preloadEffect:#"dink.wav"];
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:#"musicloop.wav"];
[WordDictionary configDictionary];
[pool release];
}
+(void)configDictionary
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Serializer * mySerializer = [[Serializer alloc] init];
[WordDictionary setDictionary:[mySerializer readApplicationPlist:#"x"]];
NSString * string;
NSString *filePath = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:#"x.txt"];
NSString *info = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
NSArray *arrayOfLines = [info componentsSeparatedByString:#"\r\n"];
[WordDictionary setDictionary:[[NSMutableDictionary alloc] init]];
[NSMutableDictionary dictionaryWithContentsOfFile:filePath];
int len = [arrayOfLines count];
for(int i = 0; i < len; i++)
{
string = [arrayOfLines objectAtIndex:i];
NSString * blankString = [NSString stringWithString:#""];
[[WordDictionary dictionary] setObject:blankString forKey:string];
double calc = ((double)i / (double)len) * 100.0;
[WordDictionary setProgress:(int)calc];
}
[mySerializer writeApplicationPlist:[WordDictionary dictionary] toFile:#"s"];
[WordDictionary setProgress:100];
[pool release];
}
Is there something I should know about using static class methods with new selector threads?
Thank you for your help
First, there are no static methods in Objective-C. There are class methods.
Secondly, your code shows both methods wrapped in autorelease pools. The warning must be coming from somewhere else.
Finally, your code leaks like a sieve. You aren't following the memory management rules. And there are some nonsense statements in there.
Specifically:
[WordDictionary setDictionary:[[NSMutableDictionary alloc] init]];
Unless +setDictionary: is breaking the memory management rules, the above leaks.
This statement [NSMutableDictionary dictionaryWithContentsOfFile:filePath]; effectively does nothing unless you do something with the return value.
Also, mySerializer is leaking.
Try running the analyzer over your code and fixing the problem. You should also read this and this.
Ah the [NSMutableDictionary dictionaryWithContentsOfFile:filePath]; was part of an experiment I was attempting to make the dictionary access faster. I should have removed it from this example.
I have just read the memory management rules, and understand that
[WordDictionary setDictionary:[[NSMutableDictionary alloc] init]]; appears to be poorly planned instantiation because I have no way to release it from within configDictionary as the reference is lost. But actually I don't ever want to release it, it lives for the entire lifetime of my application. Probably bad practice just the same.
mySerializer should definitely be released at the bottom.
I was just wondering if class methods had any special rules regarding autorelease pools and memory.
I will look over the documents you sent me and try to figure out the Analyzer, thank you for your help.
I would like to send an object back to the main thread from worker thread. However do auto-release pools work between threads? Is there anything wrong with the following code:
-(void)mainThreadReceiveResult:(id)response
{
[response retain];
/* Do some stuff with response */
[response release];
}
-(void)workerThreadDoWork
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
response * response = [[[response alloc] init] autorelease];
response->someData = [self getSomeData];
[delegate performSelectorOnMainThread:#selector(receiveResult:) withObject:response waitUntilDone:NO];
[pool release];
}
Seems to work fine. However is it possible that the worker thread could reach [pool release] before the main thread is able to retain it?
Your code shouldn't crash: performSelectorOnMainThread: retains its arguments until after the selector finishes, so your retain/release pair is superfluous.
See the documentation:
This method retains the receiver and the arg parameter until after the selector is performed.
Also: you should probably [pool drain] instead of [pool release].
This may answer your question.
Here's what he did to solve the problem. The explanation is given in that link.
- (void)runSomethingThatWillFail:(NSError **)error {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *directoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:#"/BOGUS" error:error];
[*error retain];
[pool release];
[*error autorelease];
}