Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSMutableArray in loop leaks memory even when I explicitly release it

This loop leaks memory:

int64_t i,verylongnumber;

//misc. code

for(i=0;i<verylongnumber;i++){
    NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:
            [NSNumber numberWithLongLong:65535],
            [NSNumber numberWithLongLong:65535],
            [NSNumber numberWithLongLong:65535],
            [NSNumber numberWithLongLong:65535],
            nil];
    [myArray removeAllObjects];
    [myArray release];
}

I've tried everything to keep it from leaking memory, but I can't. I think it has something to do with the NSNumbers. I assume they are created autoreleased, but does that mean I have to free them individually (i.e. use alloc)? How would I even do that? Create a separate variable for each NSNumber and insert that into the array? That seems like a lot of work. I tried [myArray removeAllObjects], but that made no difference. it is within my own thread with its own autorelease pool. I'm not sure if that makes a difference.

This fixed it:

I added an additional autorelease pool inside the loop:

int64_t i,verylongnumber;

//misc. code

for(i=0;i<verylongnumber;i++){

    NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];

    NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:
            [NSNumber numberWithLongLong:65535],
            [NSNumber numberWithLongLong:65535],
            [NSNumber numberWithLongLong:65535],
            [NSNumber numberWithLongLong:65535],
            nil];
    [myArray release];

    [pool2 drain];
}
like image 443
Synthetix Avatar asked Jul 17 '26 12:07

Synthetix


2 Answers

I'll take a stab at this..

You can remove [myArray removeAllObjects] as it is redundant. NSArray's do retain their objects, but they also release them when the array itself is deallocated.

The NSNumbers themselves are autoreleased. However if you do a very very large loop then that autoreleased memory won't actually be freed until the for loop exits and eventually the run loop as well (unless you have setup a separate NSAutoreleasePool somewhere).

So I can see how the memory usage would increase as this loop iterates, but at completion it should free the memory. How did you arrive at the conclusion that you have a leak?

like image 76
Carter Avatar answered Jul 19 '26 02:07

Carter


Are you waiting to see if the objects get released in the near future?

Autoreleased objects are released at some point in the near future. In the case above, you're looping a very long number of times creating many objects. They will not get released within the scope of that code.

In a GUI app it means after the function returns when the run loop is being run. In a console app, it's when the pool is released.

Check out:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html

Autorelease pools provide a mechanism whereby you can send an object a “deferred” release message.

The key is the deferred point.

EDIT: (after comment)

Note that you can drain the pool. The other option is to create non-autoreleased numbers (alloc/init) and explicitly release in your long running loop. depending on the code, that may be desirable since draining the pool could release objects deferred for release which code later in that loop/scope assumes is still deferred. If you want to control it, then control it.

like image 45
bryanmac Avatar answered Jul 19 '26 02:07

bryanmac



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!