Уменьшение пикового использования памяти с помощью @autoreleasepool

Я работаю над приложением для iPad, которое имеет процесс синхронизации, использующий веб-сервисы и основные данные в замкнутом цикле. Чтобы уменьшить объем памяти в соответствии с рекомендацией Apple, я периодически выделяю и очищаю NSAutoreleasePool. В настоящее время это прекрасно работает, и с текущим приложением нет проблем с памятью. Однако я планирую перейти на ARC, где NSAutoreleasePoolбольше недействителен, и хотел бы сохранить такую ​​же производительность.Я создал несколько примеров и замерил их время, и мне интересно, как лучше всего использовать ARC для достижения такой же производительности и поддержания читабельности кода.

В целях тестирования я придумал 3 сценария, каждый из которых создает строку, используя число от 1 до 10 000 000. Я запускал каждый пример 3 раза, чтобы определить, сколько времени они заняли, используя 64-битное приложение Mac с компилятором Apple LLVM 3.0 (без gdb -O0) и XCode 4.2. Я также прогнал каждый пример через инструменты, чтобы примерно увидеть пик памяти.

Каждый из приведенных ниже примеров содержится в следующем блоке кода:

int main (int argc, const char * argv[])
{
    @autoreleasepool {
        NSDate *now = [NSDate date];

        //Code Example ...

        NSTimeInterval interval = [now timeIntervalSinceNow];
        printf("Duration: %f\n", interval);
    }
}

Пакет NSAutoreleasePool [Исходный Pre-ARC] (Пиковая память: ~116 КБ)

    static const NSUInteger BATCH_SIZE = 1500;
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++)
    {
        NSString *text = [NSString stringWithFormat:@"%u", count + 1U];
        [text class];

        if((count + 1) % BATCH_SIZE == 0)
        {
            [pool drain];
            pool = [[NSAutoreleasePool alloc] init];
        }
    }
    [pool drain];

Время выполнения:
10,928158
10,912849
11.084716


Внешний @autoreleasepool (Пиковая память: ~382 МБ)

    @autoreleasepool {
        for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++)
        {
            NSString *text = [NSString stringWithFormat:@"%u", count + 1U];
            [text class];
        }
    }

Время работы:
11.489350
11.310462
11.344662


Внутренний @autoreleasepool (Пиковая память: ~61,2 КБ)

    for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++)
    {
        @autoreleasepool {
            NSString *text = [NSString stringWithFormat:@"%u", count + 1U];
            [text class];
        }
    }

Время работы:
14.031112
14.284014
14.099625


@autoreleasepool w/goto (Пиковая память: ~115 КБ)

    static const NSUInteger BATCH_SIZE = 1500;
    uint32_t count = 0;

    next_batch:
    @autoreleasepool {
        for(;count < MAX_ALLOCATIONS; count++)
        {
            NSString *text = [NSString stringWithFormat:@"%u", count + 1U];
            [text class];
            if((count + 1) % BATCH_SIZE == 0)
            {
                count++; //Increment count manually
                goto next_batch;
            }
        }
    }

Время выполнения:
10.908756
10.960189
11.018382

Оператор gotoобеспечивает наилучшую производительность, но использует goto. Есть предположения?

Обновление:

Примечание. Оператор gotoявляется обычным выходом для @autoreleasepool, как указано в документации , и не приведет к утечке памяти.

При входе автоматически высвобождается пул. При нормальном выходе (перерыв, return, goto, fall-through и т. д.) извлекается пул автовыпуска.Для совместимости с существующим кодом, если выход происходит из-за исключения, пул авторелиза не извлекается.

7
задан Joe 13 March 2012 в 00:01
поделиться