Похоже, что большая часть документации Apple избегает использования автоматически выпущенных объектов, особенно при создании графических интерфейсов, но я хочу знать, какова стоимость использования автоматически выпущенных объектов?
UIScrollView *timeline = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 20, 320, 34)];
[self addSubview:timeline];
[timeline release];
В конечном счете, следует ли мне использовать стратегию, при которой все автоматически выпускается, а использование сохранения / выпуска должно быть исключением из правил для конкретных случаев? Или я должен обычно использовать функцию сохранения / выпуска с автоматическим выпуском, который является исключением для объектов, возвращаемых из удобных методов, таких как [NSString stringWithEtc ...]?
Нет, это не сборщик мусора.





Насколько я понимаю, основным недостатком использования автозапуска является то, что вы не знаете, когда объект наконец будет выпущен и уничтожен. Это потенциально может привести к тому, что ваше приложение будет использовать намного больше памяти, чем необходимо, если у вас есть много автоматически выпущенных объектов, которые находятся рядом, но еще не выпущены.
Есть две стоимости:
(Предполагая, что у вас есть возможность избегать автоматически выпускаемых объектов.) Фактически вы без необходимости продлеваете время жизни ваших объектов. Это может означать, что объем вашей памяти растет - без необходимости. На ограниченной платформе это может означать, что ваше приложение прекращает работу, если оно превышает лимит. Даже если вы не превысите лимит, ваша система может начать подкачку, что очень неэффективно.
Дополнительные накладные расходы на поиск текущего пула автозапуска, добавление к нему автоматически выпущенного объекта и последующее освобождение объекта в конце (дополнительный вызов метода). Возможно, это не большие накладные расходы, но они могут накапливаться.
Лучшая практика на любой платформе - по возможности избегать автоматического выпуска.
Чтобы ответить на вопросы:
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.
Затраты:
Если вы хотите быть очень консервативными в использовании памяти, вам следует избегать автоматического выпуска. Однако это полезный метод, который может сделать код более читабельным. Одержимое использование удержания / освобождения подпадает под понятие «преждевременная оптимизация».
Если вы находитесь в основном потоке обработки событий Какао (что вы делаете большую часть времени), пул автозапуска очищается, когда управление возвращается обработчику событий. Если ваш метод короткий и не обрабатывает большие объемы данных, можно использовать автозапуск, чтобы отложить освобождение до конца цикла выполнения.
Опасаться автоспуска следует тогда, когда вы зациклились. Например, вы просматриваете адресную книгу пользователя и, возможно, загружаете файл изображения для каждой записи. Если все эти объекты изображений автоматически освобождены, они будут накапливаться в памяти до тех пор, пока вы не посетите всю адресную книгу. Если адресная книга достаточно велика, вам может не хватить памяти. Если вы выпустите изображения, как только закончите с ними, в цикле ваше приложение сможет повторно использовать память.
Если вы не можете избежать автозапуска внутри цикла (это делается кодом, который вы не писали и не можете изменить), вы также можете самостоятельно управлять NSAutoreleasePool внутри цикла, если это необходимо.
Поэтому не забывайте об использовании автозапуска внутри циклов (или методов, которые могут вызываться из циклов), но не избегайте этого, когда это может сделать код более читабельным.
Это не считается «лучшей практикой», особенно на платформах с ограниченными ресурсами. Обратите внимание на замечание Джима Пулса об отладке.
Что не является «лучшей практикой»? Я говорю, что за счет затрат на автоматический выпуск (с чем мы согласны) вы можете улучшить читаемость кода. Иногда это приемлемый компромисс.
Использование автоспуска - не лучшая практика.
Избегать автоматического выпуска - не лучшая практика.
Да, это так. Возможно, я мог бы спросить, на каком основании вы делаете это утверждение?
Мой собственный опыт разработки программного обеспечения для доставки. В реальном мире иногда удобочитаемость кода превосходит несущественные оптимизации. Вы слишком фундаменталисты в своих утверждениях о том, что автоспуска следует избегать любой ценой. Иногда это того стоит.
Мое утверждение основано на обсуждении с инженерами iPhone при написании (и настройке политики) образца кода iPhone (а затем и для презентаций WWDC) и последующем обсуждении с инженерами AppKit для обеспечения согласованности сообщения. Последовательное сообщение было: избегать автоспуска - лучшая практика.
Вы можете не следовать передовой практике управления памятью по другим причинам, но это не меняет того, что считается передовой практикой управления памятью.
Лучшей практикой для управления памятью Какао является использование autorelease и связанных с ним удобных методов и т. д. Лучшей практикой является переключение на ручное управление retain / release, если, и только если, объективные данные из инструментов профилирования указывают на горячие точки пула автозапуска. Даже в этом случае предпочтительно использовать аккуратно установленный NSAutoreleasePool. Забудьте, что говорит @mmalc - у моего iPhone / iPod touch больше оперативной памяти, чем у моего первого Mac с OS X ... и никто не программировал для этих машин иначе, чем они программируют для сегодняшних машин.
Я удивлен, что никто об этом еще не упомянул. Самая большая причина избегать автоматически выпускаемых объектов, когда вы не можете этого сделать, не имеет ничего общего с производительностью. Да, все упомянутые здесь проблемы с производительностью являются допустимыми для абсолютно, но самый большой недостаток автоматического выпуска состоит в том, что он значительно усложняет отладку.
Если у вас есть чрезмерно выпущенный объект, который никогда не выпускался автоматически, его тривиально легко отследить. Если у вас есть сбой, о котором сообщает пользователь, который периодически происходит с обратной трассировкой где-то к югу от NSPopAutoreleasePool, удачи ...
Это было веской причиной еще во времена Leopard, когда в Xcode еще не было встроенного статического анализатора, а инструменты - отстой. Теперь не так сложно устранить существующие ошибки, связанные с неправильным обращением с памятью, с помощью инструментов и предотвратить появление ошибок, в первую очередь, путем включения и выполнения статического анализатора.
Другие ответили, следует ли вам автоматически выпускать, но когда вы автоматически выпускаете должен, сливайте рано и сливайте часто: http://www.mikeash.com/?page=pyblog/autorelease-is-fast.html
Я должен не согласиться с Джимом Пулсом - я думаю, что нет с использованием Autorelease затрудняет отладку, потому что вы с большей вероятностью обнаружите, что случайно потеряете память. Конечно, статический анализатор Clang может уловить некоторые из этих экземпляров, но для меня небольшие накладные расходы при обычном использовании автозапуска намного затмеваются тем, что мой код с меньшей вероятностью будет содержать ошибки.
И затем, только если у меня будет жесткий цикл, который мне нужно оптимизировать, я начну смотреть на производительность. В противном случае это всего лишь преждевременная оптимизация, что обычно считается плохим.
Но разве случайная утечка памяти не более желательна, чем сбой, который невозможно отследить? Я говорю только по собственному опыту.
Джим: Я согласен с тобой, это тоже мой опыт.
Следует иметь в виду, что если вы создаете новый поток, вы должны настроить новый пул Autorelease в этом потоке, прежде чем делать что-либо еще. Даже если вы не используете объекты autorelease, есть вероятность, что что-то в API Какао есть.
Я заметил, что предоставленный вами образец кода предназначен для iPhone. Apple особо рекомендует избегать объектов с автозапуском для приложений iPhone. Я не могу найти конкретных аргументов, но они забили эту точку на WWDC.
Один выгода для использования пулов с автоматическим выпуском заключается в том, что они безопасны в отношении исключений без использования @try / @finally. У Грега Паркера («Мистер Объектив-C») есть отличный пост, объясняющий детали этого.
Я часто использую autorelease, поскольку в нем меньше кода и он более читабелен, IMO. Обратной стороной, как указывали другие, является то, что вы продлеваете время жизни объектов, тем самым временно используя больше памяти. На практике я еще не обнаружил, что чрезмерное использование autorelease является серьезной проблемой в любом приложении для Mac, которое я написал. Если высокое использование памяти кажется проблемой (это не вызвано настоящей утечкой), я просто добавляю дополнительные пулы автозапуска (после профилирования, чтобы показать мне, где они мне нужны). Но, в целом, это довольно редко. Как показано в сообщении Майка Эша (на него ссылается Грэм Ли), пулы с автоматическим выпуском имеют очень небольшие накладные расходы и работают быстро. Добавление дополнительных пулов с автоматическим выпуском требует почти нулевых затрат.
Конечно, это все для приложений Mac. В приложениях для iPhone, где память более ограничена, вы можете быть осторожны в использовании автозапуска. Но, как всегда, сначала напишите читаемый код, а затем оптимизируйте его, измеряя, где находятся медленные / интенсивные части памяти.
В наши дни я обычно использую автоматически выпущенные объекты, потому что они, как правило, приводят к более простому и удобочитаемому коду. Вы объявляете и инициализируете их, а затем позволяете выпадать из области видимости. Механически они существуют немного дольше, но с точки зрения человека, пишущего код, это эквивалентно тому, что объявленный в стеке объект в C++ автоматически разрушается, когда функция возвращается и ее фрейм уничтожается.
Хотя наблюдается потеря эффективности, в большинстве случаев она незначительна. Более серьезная проблема заключается в большем количестве существующих объектов, и последующее восстановление памяти может привести к более фрагментированному адресному пространству. Если это проблема, обычно довольно просто перейти к ручному удержанию / освобождению несколькими горячими методами и улучшить его.
Как уже говорили другие, удобочитаемость превосходит производительность в коде, чувствительном к непроизводительности. Есть ряд случаев, когда использование автоматически освобожденных объектов приводит к большей фрагментации памяти, но в любом случае, когда объект переживет пул, этого не произойдет. В таких случаях единственная цена, которую вы платите, - это поиск правильного пула автозапуска.
Старая ветка, но доработанная для новых читателей.
Я использую autorelease вместо сохранения / release в зависимости от риска ошибок автоматического выпуска, специфичных для объекта, и размера объекта. Если я просто добавляю несколько крошечных UIImageView или пару UILabels в свое представление, autorelease сохраняет код читабельным и управляемым. И когда представление будет удалено и отключено, эти подпредставления должны быть выпущены достаточно скоро.
Если, с другой стороны, мы говорим о UIWebView (высокий риск ошибок автоматического выпуска) или, конечно, о некоторых данных, которые должны быть постоянными до «смерти» объекта, следует сохранить / освободить.
Честно говоря, мои проекты еще не достигли такого большого размера, когда дополнительное «время пребывания» автоматически выпущенных объектов создало бы проблему с памятью. Для сложных приложений такая озабоченность вполне закономерна.
В любом случае, я не думаю, что универсальный подход будет правильным. Вы используете любой подход - или комбинацию подходов - подходящую для проекта, учитывая все упомянутые выше факторы.
Подождите, это просто обычная сборка мусора?