Какова стоимость использования автозапуска в Какао?

Похоже, что большая часть документации Apple избегает использования автоматически выпущенных объектов, особенно при создании графических интерфейсов, но я хочу знать, какова стоимость использования автоматически выпущенных объектов?

UIScrollView *timeline = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 20, 320, 34)];
[self addSubview:timeline];
[timeline release];

В конечном счете, следует ли мне использовать стратегию, при которой все автоматически выпускается, а использование сохранения / выпуска должно быть исключением из правил для конкретных случаев? Или я должен обычно использовать функцию сохранения / выпуска с автоматическим выпуском, который является исключением для объектов, возвращаемых из удобных методов, таких как [NSString stringWithEtc ...]?

Подождите, это просто обычная сборка мусора?

Marcin 11.10.2008 03:48

Нет, это не сборщик мусора.

mmalc 11.10.2008 13:03
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
11
2
8 120
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

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

Ответ принят как подходящий

Есть две стоимости:

  1. (Предполагая, что у вас есть возможность избегать автоматически выпускаемых объектов.) Фактически вы без необходимости продлеваете время жизни ваших объектов. Это может означать, что объем вашей памяти растет - без необходимости. На ограниченной платформе это может означать, что ваше приложение прекращает работу, если оно превышает лимит. Даже если вы не превысите лимит, ваша система может начать подкачку, что очень неэффективно.

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

Лучшая практика на любой платформе - по возможности избегать автоматического выпуска.

Чтобы ответить на вопросы:

Ultimately should I use a strategy where everything is autoreleased and using retain/release should be the exception to the rule for specific cases?

Наоборот.

Or should I generally be using retain/release with autorelease being the exception for returned objects from convenience methods like [NSString stringWithEtc...] ?

Вы должны использовать всегда, если можете, для сохранения / выпуска - в случае NSString, как правило, нет необходимости использовать методы stringWithEtc, поскольку существуют эквиваленты initWithEtc.

См. Также этот вопрос.

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

Steven Fisher 07.04.2010 23:19

Затраты:

  1. Время найти пул автозапуска текущего потока и добавить в него объект.
  2. Память, занятая объектом, пока она не будет освобождена в какой-то более поздний момент.

Если вы хотите быть очень консервативными в использовании памяти, вам следует избегать автоматического выпуска. Однако это полезный метод, который может сделать код более читабельным. Одержимое использование удержания / освобождения подпадает под понятие «преждевременная оптимизация».

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

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

Если вы не можете избежать автозапуска внутри цикла (это делается кодом, который вы не писали и не можете изменить), вы также можете самостоятельно управлять NSAutoreleasePool внутри цикла, если это необходимо.

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

Это не считается «лучшей практикой», особенно на платформах с ограниченными ресурсами. Обратите внимание на замечание Джима Пулса об отладке.

mmalc 11.10.2008 13:02

Что не является «лучшей практикой»? Я говорю, что за счет затрат на автоматический выпуск (с чем мы согласны) вы можете улучшить читаемость кода. Иногда это приемлемый компромисс.

benzado 13.10.2008 10:45

Использование автоспуска - не лучшая практика.

mmalc 15.10.2008 13:41

Избегать автоматического выпуска - не лучшая практика.

benzado 15.10.2008 23:24

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

mmalc 16.10.2008 06:45

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

benzado 22.10.2008 19:08

Мое утверждение основано на обсуждении с инженерами iPhone при написании (и настройке политики) образца кода iPhone (а затем и для презентаций WWDC) и последующем обсуждении с инженерами AppKit для обеспечения согласованности сообщения. Последовательное сообщение было: избегать автоспуска - лучшая практика.

mmalc 22.10.2008 22:07

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

mmalc 22.10.2008 22:12

Лучшей практикой для управления памятью Какао является использование autorelease и связанных с ним удобных методов и т. д. Лучшей практикой является переключение на ручное управление retain / release, если, и только если, объективные данные из инструментов профилирования указывают на горячие точки пула автозапуска. Даже в этом случае предпочтительно использовать аккуратно установленный NSAutoreleasePool. Забудьте, что говорит @mmalc - у моего iPhone / iPod touch больше оперативной памяти, чем у моего первого Mac с OS X ... и никто не программировал для этих машин иначе, чем они программируют для сегодняшних машин.

johne 06.09.2009 06:59

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

Если у вас есть чрезмерно выпущенный объект, который никогда не выпускался автоматически, его тривиально легко отследить. Если у вас есть сбой, о котором сообщает пользователь, который периодически происходит с обратной трассировкой где-то к югу от NSPopAutoreleasePool, удачи ...

Это было веской причиной еще во времена Leopard, когда в Xcode еще не было встроенного статического анализатора, а инструменты - отстой. Теперь не так сложно устранить существующие ошибки, связанные с неправильным обращением с памятью, с помощью инструментов и предотвратить появление ошибок, в первую очередь, путем включения и выполнения статического анализатора.

Peter Hosey 31.03.2010 03:06

Другие ответили, следует ли вам автоматически выпускать, но когда вы автоматически выпускаете должен, сливайте рано и сливайте часто: http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html

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

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

Но разве случайная утечка памяти не более желательна, чем сбой, который невозможно отследить? Я говорю только по собственному опыту.

Jim Puls 14.10.2008 22:58

Джим: Я согласен с тобой, это тоже мой опыт.

Schpaencoder 04.12.2008 12:09

Следует иметь в виду, что если вы создаете новый поток, вы должны настроить новый пул Autorelease в этом потоке, прежде чем делать что-либо еще. Даже если вы не используете объекты autorelease, есть вероятность, что что-то в API Какао есть.

Я заметил, что предоставленный вами образец кода предназначен для iPhone. Apple особо рекомендует избегать объектов с автозапуском для приложений iPhone. Я не могу найти конкретных аргументов, но они забили эту точку на WWDC.

Один выгода для использования пулов с автоматическим выпуском заключается в том, что они безопасны в отношении исключений без использования @try / @finally. У Грега Паркера («Мистер Объектив-C») есть отличный пост, объясняющий детали этого.

Я часто использую autorelease, поскольку в нем меньше кода и он более читабелен, IMO. Обратной стороной, как указывали другие, является то, что вы продлеваете время жизни объектов, тем самым временно используя больше памяти. На практике я еще не обнаружил, что чрезмерное использование autorelease является серьезной проблемой в любом приложении для Mac, которое я написал. Если высокое использование памяти кажется проблемой (это не вызвано настоящей утечкой), я просто добавляю дополнительные пулы автозапуска (после профилирования, чтобы показать мне, где они мне нужны). Но, в целом, это довольно редко. Как показано в сообщении Майка Эша (на него ссылается Грэм Ли), пулы с автоматическим выпуском имеют очень небольшие накладные расходы и работают быстро. Добавление дополнительных пулов с автоматическим выпуском требует почти нулевых затрат.

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

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

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

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

Старая ветка, но доработанная для новых читателей.

Я использую autorelease вместо сохранения / release в зависимости от риска ошибок автоматического выпуска, специфичных для объекта, и размера объекта. Если я просто добавляю несколько крошечных UIImageView или пару UILabels в свое представление, autorelease сохраняет код читабельным и управляемым. И когда представление будет удалено и отключено, эти подпредставления должны быть выпущены достаточно скоро.

Если, с другой стороны, мы говорим о UIWebView (высокий риск ошибок автоматического выпуска) или, конечно, о некоторых данных, которые должны быть постоянными до «смерти» объекта, следует сохранить / освободить.

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

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

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