views:

171

answers:

2

I have a really large loop in my program, and I use a lot of temporary and instance variables. As my loop keeps running, the program uses up more and more memory until it crashes. Can I get some advice on how to do correct memory management in this situation? My main question is, why is the following code wrong?

Here is the code that is causing the leak:

(void) processTrackValues:(NSMutableArray*) tags {
NSImage* trackArt = [tags objectAtIndex:5];
NSMutableArray* tempArtArray = [[NSMutableArray alloc] init];
[tempArtArray addObject:trackArt];
[tempArtArray release];
}

I also tried:

(void) processTrackValues:(NSMutableArray*) tags {
NSImage* trackArt = [tags objectAtIndex:5];
NSMutableArray* tempArtArray = [[NSMutableArray alloc] init];
[tempArtArray addObject:trackArt];
[trackArt release];
[tempArtArray release];
}

+3  A: 

You could try to reuse your temporary objects or set up your own AutoReleasePool for those objects and release it every 1000 iterations or so.

Adam Kukucka
+5  A: 

Adam's answer is correct. In pseudo code:

unsigned int iters = 0;
NSAutoreleasePool *p = nil;
while(1) {
  if (!p) p = [[NSAutoreleasePool alloc] init];
  ... do stuff here ...
  if ( iters == 1000) {
     iters = 0;
     [p drain];
     p = nil;
  }
}

Re-using temporary objects is generally a waste of time and rife with fragility.

Frankly, you should probably just do the autorelease pool dance once per every iteration through the loop and ignore any silly counters and the like until you have instrumented proof that there is overhead otherwise.

Something like:

NSAutoreleasePool *p = nil;
while(1) {
  p = [[NSAutoreleasePool alloc] init];
  ... do stuff here ...
  [p drain];
}
bbum
@bbum, a while back Mike Ash did some investigation and found that draining the pool every iteration was most efficient. I think that was recent enough to include the x86_64/ARM runtime, but can't drag up a reference right now.
Graham Lee
Would this work to release objects allocated by functions called under `... do stuff here ...`? Or do those functions need their own autoreleasepools?
Chetan
@Chetan: Autorelease pools are pushed onto a stack of pools when they are created. When you you call `[obj autorelease]`, the object is put onto the pool at the top of the stack. So objects created in functions under `... do stuff here...` will be autorelease'd onto the pool at the top of the stack.
mipadi
@graham I probably should have gone with that pattern. It really boils down to measure, measure, measure.
bbum