Насколько я понимаю, все, что создано с помощью выделить, новый или копировать, нужно выпускать вручную. Например:
int main(void) {
NSString *string;
string = [[NSString alloc] init];
/* use the string */
[string release];
}
Мой вопрос, однако, не будет ли это так же справедливо ?:
int main(void) {
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
NSString *string;
string = [[[NSString alloc] init] autorelease];
/* use the string */
[pool drain];
}
Да, ваш второй фрагмент кода вполне допустим.
Каждый раз, когда -autorelease отправляется объекту, он добавляется в самый внутренний пул autorelease. Когда пул опорожняется, он просто отправляет -release всем объектам в пуле.
Пулы автозапуска - это просто удобство, которое позволяет вам отложить отправку -релиз до «позже». Это «позже» может произойти в нескольких местах, но чаще всего в приложениях с графическим интерфейсом пользователя Cocoa происходит конец текущего цикла цикла выполнения.
Разве «самый внешний» не должен быть «самым внутренним»?
an object
должен быть an object that is a subclass of NSObject or NSProxy and doesn't override -autorelease
.
Обновлено: изменено самое внешнее на самое внутреннее.
Важно: если вы используете автоматический подсчет ссылок (ARC), вы не можете использовать пулы с автоматическим выпуском напрямую. Вместо этого вы используете блоки @autoreleasepool. От developer.apple.com/library/mac/#documentation/Cocoa/Referen ce /…
@ Спасибо Цикл выполнения - это не цикл. Это не языковая конструкция вроде for
или while
. Это скорее механизм диспетчеризации, который управляет различными состояниями выполнения и событиями в потоке.
И да и нет. В конечном итоге вы бы освободили строковую память, но «просочили» объект NSAutoreleasePool в память, используя слив вместо выпуска, если бы вы запускали это в среде со сборкой мусора (не управляемой памятью). Эта «утечка» просто делает экземпляр NSAutoreleasePool «недоступным», как любой другой объект без сильных указателей в GC, и этот объект будет очищен при следующем запуске GC, что вполне может произойти сразу после вызова -drain
:
drain
In a garbage collected environment, triggers garbage collection if memory allocated since last collection is greater than the current threshold; otherwise behaves as release. ... In a garbage-collected environment, this method ultimately calls
objc_collect_if_needed
.
В остальном это похоже на то, как -release
ведет себя без GC, да. Как утверждали другие, -release
не работает под GC, поэтому единственный способ убедиться, что пул работает правильно под GC, - через -drain
, а -drain
под не-GC работает точно так же, как -release
под не-GC, и, возможно, передает свои функциональность более понятна.
Я должен указать, что ваше утверждение «все, что вызывается с помощью new, alloc или init» не должно включать «init» (но должно включать «copy»), потому что «init» не выделяет память, а только устанавливает объект (конструктор мода). Если вы получили объект alloc'd, а ваша функция вызывала только init как таковую, вы бы не выпустили ее:
- (void)func:(NSObject*)allocd_but_not_init
{
[allocd_but_not_init init];
}
Это не потребляет больше памяти, чем вы уже начали (при условии, что init не создает экземпляры объектов, но вы в любом случае не несете ответственности за них).
Мне неудобно оставлять этот ответ принятым, если ваша информация о сливе не совсем верна. См. Обновление developer.apple.com/documentation/Cocoa/Reference/Foundation /…, и я приму его повторно.
Что неточного в ответе? В среде со сборкой мусора (как указано) слив не удаляет пул AutoReleasePool, поэтому вы используете буду утечки памяти, если вы не использовали release. Цитата, которую я перечислил, была прямо из уст лошади, документы на сливе.
Лорен: В GC, - [NSAutoreleasePool Drain] вызовет сбор. -retain, -release и -autorelease игнорируются сборщиком; вот почему -drain используется в пулах автозапуска под GC.
В документации по «сливу»: в среде с управляемой памятью это ведет себя так же, как вызов release. Таким образом, у вас будет утечка памяти нет, если вы используете «слив» вместо выпуска.
-[NSAutoreleasePool release]
в среде со сборкой мусора не работает. -[NSAutoreleasePool drain]
работает как в средах с подсчетом ссылок, так и со сборкой мусора.
Нет, ты ошибаешься. В документации четко указано, что под без GC, -drain эквивалентен -release, что означает, что NSAutoreleasePool приведет к утечке нет.
Мне было интересно, почему Xcode генерирует код с -drain, если это так. Я использовал -drain, потому что думал, что он эквивалентен -release на основе кода, сгенерированного Xcode.
«Утечка» NSAutoreleasePool
принципиально невозможно: developer.apple.com/mac/library/documentation/Cocoa/Conceptu al /…
Поскольку функции drain
и release
, кажется, вызывают путаницу, возможно, стоит уточнить здесь (хотя это описано в документация ...).
Строго говоря, с точки зрения общей картины drain
является нет эквивалентом release
:
В среде с подсчетом ссылок drain
выполняет те же операции, что и release
, поэтому они в этом смысле эквивалентны. Чтобы подчеркнуть, это означает, что вы делаете утечку пула нет, если вы используете drain
, а не release
.
В среде со сборкой мусора release
не работает. Таким образом, это не имеет никакого эффекта. drain
, с другой стороны, содержит подсказку сборщику, что он должен «собирать при необходимости». Таким образом, в среде со сборкой мусора использование drain
помогает сбалансировать очистку системы.
«Утечка» NSAutoreleasePool
принципиально невозможна. Это потому, что пулы работают как стек. Создание пула подталкивает этот пул к вершине стека пула автоматического высвобождения потоков. -release
заставляет этот пул выталкивать из стека И любые пулы, которые были помещены поверх него, но по какой-либо причине не были вытолкнуты.
Каким образом это относится к тому, что я написал?
Мне нравится, как он нашел время, чтобы выделить И. ЩЕЛЧОК!
Как уже отмечалось, ваш второй фрагмент кода верен.
Я хотел бы предложить более лаконичный способ использования пула автозапуска, который работает во всех средах (подсчет ссылок, GC, ARC), а также позволяет избежать путаницы слива / выпуска:
int main(void) {
@autoreleasepool {
NSString *string;
string = [[[NSString alloc] init] autorelease];
/* use the string */
}
}
В приведенном выше примере обратите внимание на блок @autoreleasepool. Это задокументировано здесь.
Обратите внимание, что автоматический выпуск не разрешен с ARC.
Чтобы уточнить, нужно использовать блок @autoreleasepool
с ARC.
Что я прочитал от Apple: «В конце блока пула автозапуска объектам, которые получили сообщение автозапуска в блоке, отправляется сообщение освобождения - объект получает сообщение освобождения каждый раз, когда он отправлял сообщение автозапуска в блоке».
отправка автозапуска вместо освобождения объекту продлевает время жизни этого объекта, по крайней мере, до тех пор, пока сам пул не будет опустошен (это может быть больше, если объект впоследствии будет сохранен). Объект может быть помещен в один и тот же пул несколько раз, и в этом случае он будет получать сообщение об освобождении каждый раз, когда он был помещен в пул.
где конец текущего цикла цикла выполнения, если у меня нет цикла?