@autoreleasepool блок в цикле доза не уменьшает пик памяти - PullRequest
0 голосов
/ 08 октября 2018

Мне сказали, что блок @autoreleasepool в цикле может уменьшить пиковое использование памяти, пока я не выполню тест.Тестовое устройство - iPhone 6s с iOS 11.4.1.

мой код:

@implementation BigMemObj{
    NSMutableArray *_mutArr;
}

-(instancetype)init{
    if(self = [super init]){
        _mutArr = [[NSMutableArray alloc] initWithCapacity:1024*1024*30];
        for(int i = 0; i < 1024*1024*30; i++){
            [_mutArr addObject:@(i)];
        }
    }

    return self;
}


- (void)viewDidLoad {

    NSMutableArray *arr = [[NSMutableArray alloc] init];
    for(int i = 0 ; i < 10000; i++){
        @autoreleasepool {
            BigMemObj *mem = [[BigMemObj alloc] init];
        }
    }
}

- (void)viewDidLoad {

    NSMutableArray *arr = [[NSMutableArray alloc] init];
    for(int i = 0 ; i < 10000; i++){
           BigMemObj *mem = [[BigMemObj alloc] init];
    }
}

Я запускаю оба теста 34 секунды, в тесте 1 максимальное использование памяти составляет 458M, но вВ тесте 2 наибольшее использование памяти составляет 362M.и оба теста имеют треугольную форму.

с блоком @autoreleaspool

enter image description here

без блока @autoreleaspool enter image description here

Изменилась ли реализация autoreleasepool?или компилятор дозирует некоторую оптимизацию?

Спасибо!

1 Ответ

0 голосов
/ 08 октября 2018

На самом деле все выглядит нормально.Рост, который вы видите, выглядит следующим образом:

_mutArr = [[NSMutableArray alloc] initWithCapacity:102430];
for(int i = 0; i < 1024*1024*30; i++){
    [_mutArr addObject:@(i)];
}

Итак, вы добавляете свои числа в массив _mutArr и добавляете их 1024*1024*30.Когда этот цикл завершается, _mutArr является действительным и полным, он сохраняет все эти числа.Это даже не изменится добавлением другого пула автоматического выпуска в этом цикле, потому что ваш массив не позволит освободить эти числа.

Теперь, после вызова этого конструктора, у вас есть

@autoreleasepool {
    BigMemObj *mem = [[BigMemObj alloc] init];
}

, поэтомув этот момент пул автозапуска будет исчерпан, и все цифры внутри BigMemObj экземпляра mem будут освобождены, и ваша память вернется в нормальное состояние.

Вы можете ожидать, что ваше приложение будет продолжать расти в памяти без вызова @autoreleasepool.Но нет никаких изменений, если вы удалите этот вызов.Причиной этого является то, что ни один из вашего кода вообще не использует пул автоматического выпуска.Ваш код переводит (не-ARC):

NSMutableArray *arr = [[NSMutableArray alloc] init];
for(int i = 0 ; i < 10000; i++){
    @autoreleasepool {
        BigMemObj *mem = [[BigMemObj alloc] init];
        [mem release];
    }
}
[arr release];

Но вам понадобится ваш autoreleasepool, только если он был

NSMutableArray *arr = [[NSMutableArray alloc] init];
for(int i = 0 ; i < 10000; i++){
    @autoreleasepool {
        BigMemObj *mem = [[[BigMemObj alloc] init] autorelease];
    }
}
[arr release];

*1024* Чтобы иметь ситуацию, когданеобходим пул автоматического выпуска:

NSMutableArray *allBigValues = [[NSMutableArray alloc] init];

NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"profile.png"];

for(int i = 0; i<100000; i++){
    @autoreleasepool {
        [allBigValues addObject:[UIImage imageWithContentsOfFile:path]];
        [allBigValues removeAllObjects];
    }
}

Если в этом коде вы удалите пул автоматического выпуска, он будет расти в памяти до завершения цикла.Причина этого заключается в том, что imageWithContentsOfFile использует пул автоматического выпуска, и все изображения, созданные этим методом, будут выпущены только после того, как пул будет очищен.Поскольку основной пул не будет освобожден внутри цикла, нам нужно создать еще один.

В итоге этот код работает хорошо, но как только вы удалите часть @autoreleasepool, он начнет расти в памяти и, вероятно, вылетит.ваше приложение.

Примечание 1: Вам нужно добавить изображение profile.png в ваше приложение, чтобы этот код работал (просто перетащите его среди исходных файлов, а не ресурсов).

Примечание 2: Мы используем «сток», когда речь идет о пулах, потому что это было именем метода, который вам нужно было вызывать, когда вы хотели, чтобы пул удалил свои объекты.Вот как это было:

for(int i = 0; i<100000; i++){
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [allBigValues addObject:[UIImage imageWithContentsOfFile:path]];
    [allBigValues removeAllObjects];
    [pool drain];
}
...