Как работает пул автозаполнения NSAutoreleasePool?

Как я понимаю, все, что создано с alloc, новой или копией, должно быть выпущено вручную. Например:

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];
}

Ответ 1

Да, ваш второй фрагмент кода абсолютно прав.

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

Пулы автоматической регистрации - это просто удобство, которое позволяет отложить отправку-освобождение до "позже". Это "позже" может произойти в нескольких местах, но наиболее распространенные в приложениях Cocoa GUI находятся в конце текущего цикла цикла цикла.

Ответ 2

NSAutoreleasePool: утечка против выпуска

Так как функция drain и release, по-видимому, вызывает путаницу, это может быть полезно пояснить здесь (хотя это описано в документации...).

Строго говоря, с точки зрения большой картины drain не эквивалентно release:

В среде с подсчетом ссылок drain выполняет те же операции, что и release, поэтому эти два эквивалента эквивалентны. Чтобы подчеркнуть, это означает, что вы не просачиваете пул, если используете drain, а не release.

В среде, собранной для мусора, release - это не-op. Таким образом, это не имеет никакого эффекта. drain, с другой стороны, содержит подсказку сборщику, что он должен "собирать, если необходимо". Таким образом, в среде, собранной с помощью мусора, использование drain помогает собирать коллекции системного баланса.

Ответ 3

Как уже указывалось, ваш второй фрагмент кода верен.

Я хотел бы предложить более сжатый способ использования пула автозаполнения, который работает во всех средах (подсчет ссылок, GC, ARC), а также избегает путаницы стока/выпуска:

int main(void) {
  @autoreleasepool {
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
  }
}

В приведенном выше примере обратите внимание на блок @autoreleasepool. Это описано здесь.

Ответ 4

Нет, ты ошибаешься. В документации четко указано, что при не-GC, -drain эквивалентно -release, то есть NSAutoreleasePool будет не просочиться.

Ответ 5

Я нашел, что эта ссылка дала лучшее объяснение того, когда и как использовать NSAutoReleasePool: AutoReleasePool

Ответ 6

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

Ответ 7

Что я читаю от Apple: "В конце блока пула автоопределения объекты, которые получили сообщение автореферата в блоке, отправляют сообщение о выпуске - объект получает сообщение о выпуске для каждого момента, когда ему было отправлено сообщение автореферата в блоке".

https://developer.apple.com/library/mac/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html

Ответ 8

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

Ответ 9

Да и нет. Вы в конечном итоге освободите строку памяти, но "пропустите" объект NSAutoreleasePool в память, используя денек вместо выпуска, если вы запускаете это под средой сбора собранных мусора (не управляемых памятью). Эта "утечка" просто делает экземпляр NSAutoreleasePool "недоступным", как любой другой объект без сильных указателей под GC, и объект будет очищен в следующий раз, когда GC запускается, что вполне может быть непосредственно после вызова -drain

сливного

В среде сбора мусора запускает сбор мусора, если память, выделенная с момента последней коллекции, больше, чем текущий порог; иначе ведет себя как релиз.... В среде сбора мусора этот метод в конечном итоге вызывает 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 не создает объекты, но в любом случае вы не отвечаете за них).