Question

In my understanding, if ARC is enabled, objects inside @autoreleasepool{} should be released when they are not used anymore.

However, the code

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        for (int i = 0; i < 1000000000; i++) {
            NSString *string = @"ab c";
            NSArray *array = [string componentsSeparatedByString:string];
        }
    }
    return 0;
}

leaks memory.

Instruments show that leaked objects are __NSArrayM created by -[NSString componentsSeparatedByString:]

So, the question is: why __NSArrayM objects are not being destroyed in the same loop iteration they are created?

Could anyone help me in solving this problem

Update: Thanks for the answers, it seems I used the term "memory leak" incorrectly, and misunderstood how @autoreleasepool{} works. To resolve the problem, I should have placed @autoreleasepool{} inside the for-loop.

Was it helpful?

Solution

To understand how autorelease works, compare this code below to your original:

for (int i = 0; i < 1000000000; i++)
{
    @autoreleasepool
    {
        NSString* string = @"ab c";
        NSArray* array = [string componentsSeparatedByString:string];
    }
}

Auto-released objects are marked for release when they go out of scope, but not actually released until the end of the autorelease section (which is where the autorelease pool gets drained). So the code above will release the marked objects every time around the loop whereas your original code would only release them all at the end of the loop.

Auto-release pools can be nested, the closest one is used when an object is autoreleased. This allows you to return objects from functions like [NSString stringWithFormat:@"%d", i]; - the returned string has a retain count of 1 but is marked for auto-release - you can use it temporarily, but if you need to keep it for later use you need to retain it (which happens when you assign it to a strong reference). So when you retain it, the retain count goes to 2, then later when it is auto-released the retain count goes to 1 and all is good. If you never retain it then when auto-released the retain count goes to 0 and the object is dealloced.

OTHER TIPS

Your understanding is wrong

  1. This doesn't have anything to do with ARC
  2. It's not garbage collection, so the objects are not released when they stop being used
  3. Autorelease pool releases objects when it's drained ([NSAutoreleasePool drain]) or destroyed. You are not draining the pool explicitely so it would be drained only once, just before return.

In my understanding, if ARC is enabled, objects inside @autoreleasepool{} should be released when they are not used anymore.

OK, take a step back and actually think about this for a second. ARC is not some magical catch-all for every memory leak, it's still manual retain-release, just compiler inserted manual retain-release. @autoreleasepool {} does not obviate the need for prudence when giving examples of "memory leaks," nor does it give you the right to allocate 1 billion objects and call it a framework bug. As it turns out, what you've done is probably overloaded the autorelease pool it hands you, and you either aren't waiting long enough for the loop to terminate properly, or you're getting killed by the OS (I'd bet more on the latter than the former). Having run this myself, I can confirm that the given autorelease pool does drain away the Gigs of RAM this allocates, it just takes quite a while.

If you remove the loop, or even shorten its duration (100, or even 1000 should suffice), you can see that there's absolutely no leakage of objects, and that everything goes the way of the dinosaur correctly:

enter image description here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top