Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSNumber possible memory leak

Create an ARC new project and inject this code in didFinishLaunchingWithOptions.

for (int i=0; i < 1000000; i++) {
    NSNumber* num = [NSNumber numberWithInt:i];
    NSLog(@"%@", num);
}

NSLog(@"over");

Application's memory will increase. Also, at the end of the for loop, memory will not decrease.

However, if you replace in that same for loop:

NSNumber* num = [NSNumber numberWithInt:i];

by

NSNumber* num = [[NSNumber alloc] initWithInt:i];

Then memory will remain stable.

Is this an expected behaviour?

EDIT:

Ok, so let's put didFinishLaunchingWithOptions on side for the moment. You can still put in viewDidLoad and remove a zero in order to reach the end of for loop quicker Memory of the app will grow till ~11 MB. When the for loop ends, the memory will NOT decrease. It remains at ~11 MB.

- (void)viewDidLoad {
    [super viewDidLoad];

    for (int i=0; i < 100000; i++) {
        NSNumber* num = [NSNumber numberWithInt:i];
        NSLog(@"%@", num);
    }

    NSLog(@"over");
}

If you go with :

- (void)viewDidLoad {
    [super viewDidLoad];

    @autoreleasepool {
        for (int i=0; i < 100000; i++) {
            NSNumber* num = [NSNumber numberWithInt:i];
            NSLog(@"%@", num);
        }
    }

    NSLog(@"over");
}

Surprise! Surprise! You'll have the exact same behaviour. You'll reach ~11 MB and memory will NOT decrease. However, putting the @autorelease inside the loop will work... But here, I'm not trying to make things work but understand why memory is not drained at the end of the for loop.

So, question is still open.

like image 935
HappyCode Avatar asked Oct 21 '22 09:10

HappyCode


1 Answers

This is expected. When you allocate the NSNumber with alloc/init, ARC will free it as soon as it is no longer needed.

When you allocate it with a convenience method like numberWithInt: what you will obtain is an object allocated in an autorelease pool. Until the autorelease pool is drained, you memory will not be freed. However, you can create an autorelease pool for your loop like this:

for (int i=0; i < 1000000; i++) @autoreleasepool {
    NSNumber* num = [NSNumber numberWithInt:i];
    NSLog(@"%@", num);
}

NSLog(@"over");

This should free the number after each look iteration.

You can get further details here: Memory Management Policy

like image 82
Jorge Avatar answered Oct 27 '22 19:10

Jorge