NSEnumerator memory leak

2019-07-27 12:13发布

This leaks like mad, due to the way I use enumerators. Why? It leaks even more severely if I don't release the enumerator - I understand that much.. but I don't understand why this still leaks.

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

   // insert code here...
   NSLog(@"Hello, World!");

   // Create an array and fill it with important data!  I'll need to enumerate this.
   NSMutableArray *myArray = [[NSMutableArray alloc] initWithCapacity:300];

   int i;
   for(i = 0; i < 200; i++)
     [myArray addObject:[NSNumber numberWithInt:i]];

   while(1)
   {
      NSEnumerator *enumerator = [myArray objectEnumerator];
      // Imagine some interesting code here
      [enumerator release];
   }

   // More code that uses the array..

   [pool drain];
   return 0;
}

2条回答
疯言疯语
2楼-- · 2019-07-27 12:52

It doesn't leak, per se — and you shouldn't release the enumerator.

A memory leak is when memory is left allocated but can no longer be released (typically because you no longer have a pointer to it). In this case, the enumerator will be released when the autorelease pool drains, but you're preventing the program from reaching that line with your loop. That's why the enumerators pile up. If you change the loop to:

while(1)
{
    NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
    NSEnumerator *enumerator = [myArray objectEnumerator];
    [innerPool drain];
}

you'll find that your memory consumption remains constant, because the enumerator will be properly released at the end of each iteration.

查看更多
时光不老,我们不散
3楼-- · 2019-07-27 12:57

It leaks because your outermost autorelease pool only gets to do its thing once. Any autoreleased objects created within the while(1) loop will just sit around consuming memory until your program flow gets to the [pool drain] at the end.

To avoid this, create additional nested autorelease pools inside your loop, like this:

while(1) {
    NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
    // .. Do a bunch of stuff that creates autoreleased objects
    [innerPool drain];
}

This approach is similar to how AppKit works, creating and draining a new autorelease pool for each iteration through its event loop.

查看更多
登录 后发表回答