Лучший способ периодически истощать пул авто-релиза в длительном фоновом потоке? - PullRequest
5 голосов
/ 27 сентября 2010

В документации разработчика написано:

Если ваше приложение или поток является долгоживущим и потенциально генерирует много автоматически выпущенных объектов, вам следует периодически сливать и создавать пулы автоматического выпуска (как это делает Application Kit в основном потоке); в противном случае автоматически высвобождаемые объекты накапливаются, а объем памяти увеличивается. Если, однако, ваш отдельный поток не выполняет вызовы Какао, вам не нужно создавать пул автоматического выпуска.

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

- (void)startThread
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    accessoryRunLoop = [NSRunLoop currentRunLoop];

    //Add a dummy port to avoid exiting the thread due to no ports being found
    [accessoryRunLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];

    while(accessoryThreadIsRunning)
    {
        //Keep the thread running until accessoryTheadIsRunning == NO
        [accessoryRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }

    [pool release];
}

Мои варианты:

1) Добавьте счетчик в то время (accessoryThreadIsRunning), чтобы каждые 50 или 100 раз он истощал пул автоматического выпуска и создавал новый.

2) Каждый раз, когда я выполняю метод в этом потоке (используя executeSelector: onThread :), я могу создать пул автоматического выпуска и затем освободить его в конце метода.

3) Создайте таймер, чтобы пул сливался, а затем периодически создавался.

Я думаю, что вариант 1 - лучший, но хотел бы знать, есть ли другой способ, которым я должен сделать это. Спасибо!

Ответы [ 4 ]

4 голосов
/ 27 сентября 2010

Я бы начал с очень простого и просто создавал / истощал пул при каждом прохождении цикла.

Если во время анализа производительности он обнаруживается как горлышко бутылки, исправьте его.

Сохраняйте простоту, пока анализ не покажет, что требуется сложность.

<Ч />

Я просто перечитал твой вопрос и понял, что в моем ответе что-то совершенно тупое. Если вы запускаете цикл выполнения, должен автоматически управлять пулом автоматического выпуска; он должен создать пул в верхней части цикла и сливать его в конце каждого прохода через цикл.

Вам нужно циклировать один самостоятельно, если у вас есть другие вещи, происходящие за пределами runloop. Это тот случай?

В любом случае, да, шаблон выглядит так:

 while(...) {
    ... create pool ...
    ... do stuff ...
    ... drain pool ...
 }
2 голосов
/ 28 сентября 2010

Слейте его каждый раз.Как уже говорили другие, слив автозапуска дешевый.

Более того, НЕ слив его может быть очень дорогостоящим.Если у вас в пуле авто-выпусков достаточно ресурсов, чтобы вызвать подкачку страниц, вы вызываете дисковый ввод-вывод, а дисковый ввод-вывод буквально в тысячи, если не в миллионы раз дороже, чем запуск связанного списка, вызывающего выпуск содержимого.(и в таких системах, как iOS, у которых нет подкачки страниц, большое количество дополнительных объектов, ожидающих автоматического выпуска, может привести к предупреждению о нехватке памяти, что может привести к принудительному завершению работы приложений, или из-за того, что приложение переднего плана выпустит группу представлений Nib или что-то подобноезатем он должен будет воссоздать позже ... или он может просто заставить ваше приложение завершиться).

Даже если вы не используете «достаточно» дополнительной памяти, чтобы вызвать предупреждения о недостаточном объеме памяти или подкачку страниц, вы будетезапустив большой список элементов для слива.Больше доступа к памяти будет между вашим самым новым автоматическим выпуском и самым старым.Существует гораздо большая вероятность того, что самый старый элемент автоматического выпуска теперь находится дальше в иерархии памяти, поэтому ваш выпуск может иметь ошибки в кэше по сравнению с попаданием в кэш L1 или L2.Так что, может быть, в 100 раз дороже.Кроме того, память, которую вы освободили (и, возможно, была горячей в кэше), могла бы быть повторно использована другим объектом.

Таким образом, выполнение автоматического выпуска каждые 50-100 раз может даже не оказаться преждевременной оптимизацией.

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

0 голосов
/ 28 сентября 2010

Обычный способ - да, держать счетчик и сливать каждые 50 или около того раз, но, как сказал bbum, просто начните с осушения бассейна в каждой петле и продолжайте оттуда. ИЛИ вы можете -init объекты, которые вам нужны, и не создавать автоматически выпущенных объектов. (просто держитесь подальше от фабричных методов) Не забывайте, однако, -release все ваши объекты.

0 голосов
/ 28 сентября 2010

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

...