По большей части с ARC (Автоматический подсчет ссылок) нам вообще не нужно думать об управлении памятью с объектами Objective-C. Больше не разрешено создавать NSAutoreleasePool
s, однако есть новый синтаксис:
@autoreleasepool {
…
}
Мой вопрос: зачем мне это нужно, когда я не должен вручную выпускать / автоматически выпускать?
РЕДАКТИРОВАТЬ: Подводя итог, что я получил от всех ответов и кратких комментариев:
Новый синтаксис:
@autoreleasepool { … }
это новый синтаксис для
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
…
[pool drain];
Важнее:
- ARC использует
autorelease
так же, как иrelease
. - Для этого нужен пул автоматических выпусков.
- ARC не создает пул автоматических релизов для вас. Тем не мение:
- В главном потоке каждого приложения Cocoa уже есть пул авто-релизов.
- Есть два случая, когда вы можете использовать
@autoreleasepool
:- Когда вы находитесь во вторичном потоке и нет пула автоматического выпуска, вы должны создать свой собственный для предотвращения утечек, таких как
myRunLoop(…) { @autoreleasepool { … } return success; }
. - Когда вы хотите создать более локальный пул, как показал @mattjgalloway в своем ответе.
- Когда вы находитесь во вторичном потоке и нет пула автоматического выпуска, вы должны создать свой собственный для предотвращения утечек, таких как
Ответы:
ARC не избавляется от удержаний, выпусков и авто-выпусков, он просто добавляет нужные вам. Таким образом, все еще есть вызовы для сохранения, есть вызовы для освобождения, все еще есть вызовы для автоматического выпуска и все еще существуют пулы автоматического выпуска.
Одна из других изменений , которые они сделали с новым компилятором Clang 3.0 и ARC является то , что они заменили
NSAutoReleasePool
с@autoreleasepool
директивой компилятора.NSAutoReleasePool
в любом случае, он всегда был чем-то вроде особого «объекта», и они сделали это так, чтобы синтаксис его использования не путался с объектом, так что он, как правило, немного проще.В общем, вам нужно,
@autoreleasepool
потому что есть еще пулы автоматических выпусков, о которых нужно беспокоиться. Вам просто не нужно беспокоиться о добавлении вautorelease
звонки.Пример использования пула авто релизов:
Конечно, очень надуманный пример, но если бы у вас не было
@autoreleasepool
внутреннего внешнегоfor
цикла, вы бы выпустили 100000000 объектов позже, а не 10000 каждый раз вокруг внешнего-for
цикла.Обновление: также посмотрите этот ответ - https://stackoverflow.com/a/7950636/1068248 - почему
@autoreleasepool
нет ничего общего с ARC.Обновление: я взглянул на внутреннюю часть того, что здесь происходит, и написал это в своем блоге . Если вы посмотрите туда, то увидите, что именно делает ARC и как новый стиль
@autoreleasepool
и как он вводит область видимости используется компилятором для вывода информации о том, что требуется, релизы и авто-релизы требуются.источник
@autoreleasepool
мне? Если я не контролирую то, что автоматически высвобождается или освобождается (ARC делает это для меня), как я должен знать, когда настраивать пул автоматического высвобождения?@autoreleasepool
ничего не высвобождает Он создает пул автоматического выпуска, поэтому, когда будет достигнут конец блока, любые объекты, которые были автоматически освобождены ARC, когда блок был активен, будут отправлены сообщения об освобождении. Расширенное руководство по программированию управления памятью от Apple объясняет это так:источник
release
сообщение, но если счет сохранения> 1, объект НЕ будет освобожден.Люди часто неправильно понимают ARC для какой-то сборки мусора или тому подобного. Правда в том, что через некоторое время люди в Apple (благодаря проектам llvm и clang) осознали, что администрирование памяти Objective-C (все и
retains
иreleases
т. Д.) Может быть полностью автоматизировано во время компиляции . Это просто путем чтения кода, даже до его запуска! :)Для этого есть только одно условие: мы ДОЛЖНЫ следовать правилам , иначе компилятор не сможет автоматизировать процесс во время компиляции. Таким образом, чтобы гарантировать , что мы никогда не нарушать правила, мы не имеем права явно записи
release
,retain
и т.д. Эти вызовы автоматически впрыскивается в наш код компилятором. Поэтому внутри у нас еще естьautorelease
с,retain
,release
и т.д. Это просто нам не нужно писать их больше.A ARC является автоматическим во время компиляции, что намного лучше, чем во время выполнения, как сборка мусора.
У нас все еще есть,
@autoreleasepool{...}
потому что наличие этого не нарушает ни одно из правил, мы можем свободно создавать / истощать наш пул в любое время, когда нам это нужно :).источник
Это потому, что вам все еще нужно предоставить компилятору подсказки о том, когда безопасным для автоматически выпущенных объектов является выход из области видимости.
источник
@autoreleasepool
потому что я не знаю, может ли ARC решить что-то сделать автоматически?Цитируется по адресу https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html :
...
источник
Пулы автоматического выпуска требуются для возврата вновь созданных объектов из метода. Например, рассмотрим этот кусок кода:
Строка, созданная в методе, будет иметь счетчик единиц. Теперь, кто должен сбалансировать это количество с выпуском?
Сам метод? Невозможно, он должен вернуть созданный объект, поэтому он не должен выпускать его до возвращения.
Вызывающий метод? Вызывающая сторона не ожидает извлечения объекта, который должен быть освобожден, имя метода не подразумевает создание нового объекта, оно только говорит о том, что объект возвращен, и этот возвращенный объект может быть новым, требующим освобождения, но может хорошо быть существующим, которого нет. То, что метод возвращает, может даже зависеть от некоторого внутреннего состояния, поэтому вызывающая сторона не может знать, должен ли он освободить этот объект, и это не должно заботить.
Если вызывающая сторона должна всегда освобождать все возвращаемые объекты по соглашению, то каждый объект, который не был вновь создан, всегда должен быть сохранен до возвращения его из метода, и он должен быть освобожден вызывающей стороной, как только он выходит из области видимости, если только он возвращается снова. Во многих случаях это было бы крайне неэффективно, так как во многих случаях можно полностью избежать изменения количества записей, если вызывающая сторона не всегда освобождает возвращаемый объект.
Вот почему существуют пуски авто-релиза, поэтому первый метод фактически станет
Вызов
autorelease
объекта добавляет его в пул автоматического выпуска, но что это действительно означает, добавляя объект в пул автоматического выпуска? Что ж, это значит сказать вашей системе: « Я хочу, чтобы вы выпустили этот объект для меня, но через некоторое время, а не сейчас; у него есть счет сохранения, который должен быть уравновешен выпуском, иначе память утечет, но я не могу сделать это сам прямо сейчас, так как мне нужно, чтобы объект остался живым за пределами моей текущей области видимости, и мой вызывающий объект не сделает это и для меня, он не знает, что это необходимо сделать, поэтому добавьте его в свой пул, и как только вы очистите его бассейн, также очистить мой объект для меня. "С ARC компилятор решает за вас, когда сохранить объект, когда освободить объект и когда добавить его в пул авто-выпуска, но он все еще требует наличия пулов авто-выпуска, чтобы иметь возможность возвращать вновь созданные объекты из методов без утечки памяти. Apple только что провела несколько оптимизаций в сгенерированном коде, которые иногда устраняют пулы автоматического выпуска во время выполнения. Эти оптимизации требуют, чтобы как вызывающий, так и вызываемый использовали ARC (помните, что смешивание ARC и non-ARC допустимо и также официально поддерживается), и если это действительно так, то это можно узнать только во время выполнения.
Рассмотрим этот код ARC:
Код, который генерирует система, может вести себя как следующий код (это безопасная версия, которая позволяет свободно смешивать код ARC и код, не являющийся ARC):
(Обратите внимание, что удержание / отпускание в вызывающей стороне является просто защитным сохранением, оно не является строго обязательным, код был бы совершенно правильным без него)
Или он может вести себя как этот код, в случае, если оба обнаруживают использование ARC во время выполнения:
Как вы можете видеть, Apple устраняет атуорелизу, а также задерживает высвобождение объектов при разрушении пула, а также сохраняет безопасность. Чтобы узнать больше о том, как это возможно и что на самом деле происходит за кулисами, прочитайте этот пост в блоге.
Теперь к актуальному вопросу: зачем использовать
@autoreleasepool
?Для большинства разработчиков сегодня есть только одна причина использовать эту конструкцию в своем коде, а именно, уменьшить объем памяти, где это применимо. Например, рассмотрим этот цикл:
Предположим, что каждый вызов
tempObjectForData
может создать новый,TempObject
который возвращается авто-релиз. Цикл for создаст миллион таких временных объектов, которые все собраны в текущем автозапуске, и только после уничтожения этого пула все временные объекты также будут уничтожены. Пока это не произойдет, у вас есть миллион таких временных объектов в памяти.Если вы вместо этого напишите код:
Затем каждый раз при запуске цикла for создается новый пул, который уничтожается в конце каждой итерации цикла. Таким образом, в любой момент времени в памяти висит не более одного временного объекта, несмотря на то, что цикл выполняется миллион раз.
В прошлом вам часто приходилось самостоятельно управлять автозапусками при управлении потоками (например, с использованием
NSThread
), поскольку только основной поток автоматически имеет пул автозапуска для приложения Cocoa / UIKit. Однако сегодня это в значительной степени наследие, поскольку сегодня вы, вероятно, не будете использовать потоки для начала. Вы бы использовали GCDDispatchQueue
илиNSOperationQueue
s, и оба они управляют пулом автоматического выпуска верхнего уровня для вас, созданным перед запуском блока / задачи и уничтоженным, как только закончите с ним.источник
Похоже, в этой теме много путаницы (и, по крайней мере, 80 человек, которые, вероятно, сейчас смущены этим и думают, что им нужно посыпать @autoreleasepool вокруг своего кода).
Если проект (включая его зависимости) использует исключительно ARC, тогда @autoreleasepool не нужно использовать и ничего полезного не будет делать. ARC будет обрабатывать освобождение объектов в нужное время. Например:
дисплеи:
Каждый объект тестирования освобождается, как только значение выходит из области видимости, не дожидаясь выхода из пула автоматического выпуска. (То же самое происходит с примером NSNumber; это просто позволяет нам наблюдать за разлочкой.) ARC не использует autorelease.
Причина, по которой @autoreleasepool по-прежнему разрешена, заключается в смешанных проектах ARC и не-ARC, которые еще не полностью перешли на ARC.
Если вы обращаетесь к не-ARC-коду, он может вернуть объект с автоматическим освобождением. В этом случае вышеприведенный цикл будет протекать, поскольку текущий пул автоматического выпуска никогда не будет завершен. Вот где вы хотели бы поместить @autoreleasepool вокруг блока кода.
Но если вы полностью перешли на ARC, забудьте об автозапуске.
источник
+ (Testing *) testing { return [Testing new] }
. Тогда вы поймете, что Deloc не будет вызван до позже. Это исправлено, если вы оберните цикл внутри@autoreleasepool
блока.+ (Testing *) testing { return [Testing new];} + (void) test { while(true) NSLog(@"p = %p", [self testing]);}
[UIImage imageWithData]
в уравнение, то внезапно я начал видеть традиционноеautorelease
поведение, требующее@autoreleasepool
поддержания пика памяти на некотором разумном уровне.