Почему это для цикла кровотечения памяти?

Я использую ARC для своего проекта iOS и использую библиотеку SSKeychain для доступа / сохранения элементов в цепочке для ключей. Я ожидаю, что мое приложение будет обращаться к элементам цепочки для ключей один раз каждые 10 секунд или около того (для доступа к токену безопасности API) при пиковой нагрузке, и поэтому я хотел протестировать эту библиотеку, чтобы увидеть, как она обрабатывает при частом вызове. Я сделал этот цикл для имитации безумного количества звонков и заметил, что он расходует значительный объем памяти (~75 МБ) при запуске на iPhone (не на симуляторе):

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSUInteger beginMemory = available_memory();
        for (int i = 0; i < 10000; ++i) {

            @autoreleasepool{
                NSError *  error2 = nil;
                SSKeychainQuery*  query2 = [[SSKeychainQuery alloc] init];
                query2.service = @"Eko";
                query2.account = @"loginPINForAccountID-2";
                query2.password = nil;
                [query2 fetch:&error2];
            }
        }
        NSUInteger endMemory = available_memory();

        NSLog(@"Started with %u, ended with %u, used %u", beginMemory, endMemory, endMemory-beginMemory);
    });

    return YES;
}

static NSUInteger available_memory(void) {
    // Requires #import <mach/mach.h>
    NSUInteger result = 0;
    struct task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size) == KERN_SUCCESS) {
        result = info.resident_size;
    }
    return result;
}

Я использую SSKeychain, который можно найти здесь. Этот тест отбирает около ~ 75 Мб памяти независимо от того, хранятся ли вещи в цепочке для ключей.

Есть идеи, что происходит? Моя методология тестирования несовершенна?

2 ответа

Решение

Я запустил ваш код под инструментом Leaks, и это то, что я увидел из трека Allocations.

Трек Распределения

Это то, что вы ожидаете - много памяти выделяется во время цикла, а затем освобождается.

Глядя на детали, которые вы видите -

подробность

Постоянные байты в куче 2,36 МБ - это память, фактически используемая приложением "сейчас" (т.е. после цикла с приложением "на холостом ходу")

Постоянные объекты 8646 - опять же, количество объектов, выделенных "сейчас".

Временные объекты 663,288 - общее количество объектов, созданных в куче за время существования приложения. Из разницы между временным и постоянным видно, что большинство из них были выпущены.

Всего байт 58,70 МБ - это общий объем памяти, выделенный во время выполнения. Не общее количество используемой памяти, а общее количество выделенных ресурсов независимо от того, были ли впоследствии выделены эти выделения.

Разница между светлой и темно-розовой полосой также показывает разницу между текущим "активным" использованием памяти и общим использованием.

Из трека Leak Checks также видно, что утечек не обнаружено.

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

Теперь я мог бы предположить, что, приложив усилия для увеличения кучи для поддержки всех этих объектов, iOS не собирается выпускать теперь освобожденную кучу памяти обратно в систему; Вполне возможно, что вашему приложению может понадобиться снова большое пространство кучи позже, поэтому ваш код сообщает, что используется много памяти, и поэтому вам следует опасаться пытаться создавать свои собственные инструменты, а не использовать доступные инструменты.

Вы должны использовать инструменты, чтобы выяснить, где / что вызывает утечку. Это очень хороший инструмент, чтобы знать, как использовать.

Эта статья немного устарела, но вы должны понять основную суть.

Рэй Вендерлих - Инструменты

Исходя из комментария Paulw11, я наткнулся на это,

От NSAutoreleasePool Класс Ссылка:

Application Kit создает пул автоматического выпуска в главном потоке в начале каждого цикла цикла событий и сливает его в конце, освобождая тем самым любые автоматически выпущенные объекты, сгенерированные во время обработки события.

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

Другие вопросы по тегам