NSAutoreleasepool leaking - Don't understand why? - iphone

I have this code:
NSNumber *num;
NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];
for (int i=0; i<images_count; i++) {
num = [NSNumber numberWithInt:images_count];
[self performSelectorInBackground:#selector(loadData:) withObject:num];
}
[apool release];
[num release];
and it generates the following error:
2011-06-17 03:10:30.768 CHARLIE[2456:6c03] * __NSAutoreleaseNoPool(): Object 0x703d0f0 of class __NSArrayI autoreleased with no pool in place - just leaking
I don't understand why its leaking, can someone please explain how to fix this?
Thanks a lot,
Jack

There are a couple of issues with that code.
The lack of an autorelease pool is probably due to the loadData: method running without an autorelease pool.
The [num release] is nonsense.
Spawning a thread per every iteration of that loop is pretty much guaranteed to be the least performant possible approach to parallelizing image loading.

Related

Memory leak of an NSMutableArray using Instruments

According to the leak instrument in XCode it's saying this line is giving a memory leak (100%)?
self.unsentPatients = [[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]];
I'm correctly releasing etc. on dealloc (which is definitely being ran) so I don't understand where I am going wrong?
It's only a small leak and Analysis doesn't come up with anything, but nonetheless it's still a leak.
Kind regards,
Dominic
There are many things wring with this code.
I'm assuming that the property is retaining the value, then you should not assign the value the way you are doing now, but more like:
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]];
self.unsentPatients = temp;
[temp release], temp = nil;
or
self.unsentPatients = [[[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]] autorelease];
You should also avoid using the self. syntax in dealloc or init, which will call a mutator.
In multithreaded environment this could give problems.
So the correct dealloc would be:
- (void) dealloc {
[unsentPatients release], unsentPatients = nil;
[super dealloc][;
}

ObjC threading and non-void functions memory management

Ok, so my question is something I have been looking for for a while. Say the method "first" has been detached as a new thread.
-(void)first{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int a;
NSMutableArray *array = [self getArray];
[pool drain];
}
-(NSMutableArray *)getArray{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *ar = [NSMutableArray array];
[ar addObject:[NSString stringWithString:#"Hello"]];
return ar;
[pool drain];
}
My issue is that if i drain the pool after the object is returned, the pool doesnt get drained, and its leaked, however if i drain it before i return the array i cannot release the array because obviously its going to be needed...
This may be something thats really obvious, and i'm just missing but i am really confused. Thanks in advance.
It is unnecessary to have a second autorelease pool in the getArray method.
If, for some reason, you wanted to have an ARP in the getArray method, you'd probably implement it like this:
- (NSMutableArray *)getArray {
NSMutableArray *ar = [NSMutableArray array];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//do stuff
[pool drain];
return ar;
}
You technically can leave the pool un-drained, and it will get drained automatically when a "higher" pool gets drained, but IMO that's a sign of some really poorly designed code.

Why no retain is needed in my code but it works

I have a class
#implementation MyClass
- (void) foo
{
ivar = [NSString stringWithString:#"ivar"];
}
- (void) bar
{
NSLog(#"%#", ivar);
}
And main.m
MyClass * m = [[MyClass alloc] init];
[m foo];
[m bar];
Why no retain is needed for stringWithString?
Can you show me an example where retain is needed?
Its because the autorelease pool had no time to drain its content. Here is a crashing example:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
MyClass *m = [[MyClass alloc] init];
[m foo];
[pool drain];
[m bar];
The autorelease pool that holds the string in your example belongs to 99% to the current runloop which creates a new pool at the begin of the event loop and then drains it at the end.
Why no retain is needed for stringWithString?
Because the autorelease pool is not being drained between line 2 and line 3 (as it would be in a Cocoa app as soon as your code returns control to the run loop).
You can start by reading Memory Management Programming Guide and look at this tutorial.
Have a look at Memory Management Rules from Apple. In your case, you did not alloc/retain/net the NSString so you don't "own" it and therefore you do not need to release it.
Internally, NSString would return you a autoreleased object. If you don't retain it then you'll lose reference to it if it gets dealloced by an autorelease pool.

iPhone Autoreleasepool and allocations

I've been reading about autoreleasepool but there is a point which is a bit unclear to me. I have some functionality using threads that required seperate memory managment using autoreleasepool.
In the following example is correct
-(void) doSomething {
NSAutorelease *pool = [[NSAutorelasepool alloc] init];
NSString *myString = #"Hello";
[pool release];
}
Is this correct?
-(void) doSomething {
NSAutorelease *pool = [[NSAutorelasepool alloc] init];
NSString *myString = [[NSString alloc] initWithString:#"Hello"];
[pool release];
}
or this?
-(void) doSomething {
NSAutorelease *pool = [[NSAutorelasepool alloc] init];
NSString *myString = [[NSString alloc] initWithString:#"Hello"];
[myString release];
[pool release];
}
My question is owned objects created in the scope of the autorelease pool need to be relased specifically or are the taken care of when the autorelasepool is been released?
Teo
Autorelease pool handles the autoreleased objects. If you own an object (via alloc or copy or retain) then you must release it. So your 2nd example is not correct. As you have allocated the string, you own it and you must release it.
An autorelease pool is created for the main thread. (You can look into the main function if you want). Every thread need its own autorelease pool to manage autoreleased objects. That's why if you create another thread then you must create an autorelease pool for that thread. Even if you don't create autoreleased object in the thread, you should create this as the library calls in that thread may create autoreleased objects. Even if you are sure that no library calls are making autoreleased objects then you also should create them as that is the best practice, specially if you are working on big project which is developed and maintained by multiple people.
You only need to create your own autorelease pool when you are creating a bunch of
autoreleased objects you want to garbage collect immediately. However, you are correct in that you don't want to reference any "autoreleased" objects you create after you release the pool. Autoreleased objects (which you don't retain) are destroyed when the pool is drained.
Since none of the objects in your example are autoreleased, creating your own autorelease pool is essentially a no-op.
Neither of your examples needs an autorelease pool. Autorelease pools only take care of autoreleased objects:
NSArray *foo = [NSArray array];
NSObject *bar = [[[NSObject alloc] init] autorelease];
Your first string is initialized using a string literal and therefore is probably special with respect to memory management (maybe someone else knows more). Your second string leaks, the pool does not make a difference. Your third string is released correctly, again the pool does not make a difference.
This is where you would need a pool:
- (void) someMethodThatRunsOnAThread {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *foo = [#"foo" uppercaseString];
[pool drain];
}
Here the foo string would leak if the pool wasn’t there. Note that I’m calling drain instead of release on the pool – on iOS there’s not a difference, but in garbage-collected environments the two differ, so it’s probably better to get in the habit of calling the right one.
Also note that you may need a pool even though you don’t autorelease any objects yourself, there could be many memory operations done somewhere in the code you’re calling in your method.
Think that this should be something like this:
-(void) doSomething {
NSAutorelease *pool = [[NSAutorelasepool alloc] init];
NSString *myString = [[[NSString alloc] initWithString:#"Hello"] autorelease];
// or create string like this (automatically autoreleased)
NSString *myString = [NSString stringWithString:#"Hello"];
[pool release];
}
You must send autorelease message, to objects inside autorelease pool. They will be released when release message is sent to pool.

How do I create a local autorelease pool to save up memory?

Apple says that this is a good idea for saving memory. What would that look like in code?
Usualy you don't need to create autorelease pool, because system cares about this. But, sometimes you need to do this. It's usualy in big loops. Code would look like this:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i;
for (i = 0; i < 1000000; i++) {
id object = [someArray objectAtIndex:i];
// do something with object
if (i % 1000 == 0) {
[pool release];
pool = [[NSAutoreleasePool alloc] init];
}
}
[pool release];
Autorelease pools are kept as a stack: if you make a new autorelease pool, it gets added to the top of the stack, and every autorelease message puts the receiver into the topmost pool.