Что такое diff b / w autoreleaspool и release [duplicate]

Ну, простыми словами:

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

Итак, как это решить:

  1. Отладить и отпустить отладчик ... Он сразу приведет вас к переменной, которая сломана ... Теперь ваша задача - просто исправить это. Используя новое ключевое слово в соответствующем месте.
  2. Если это вызвано некоторыми командами базы данных, потому что объект отсутствует, все, что вам нужно сделать, это выполнить нулевую проверку и обработать его:
    if (i == null) {
        // Handle this
    }
    
  3. Самый сложный. если GC уже собрал объект ... Это обычно происходит, если вы пытаетесь найти объект, используя строки ... То есть, найдя его по имени объекта, может случиться, что GC, возможно, уже очистил его ... Это трудно найти и станет проблемой. Лучшим способом решения этой проблемы является выполнение нулевых проверок везде, где это необходимо в процессе разработки. Это сэкономит вам много времени.

Поиск по имени означает, что некоторые фреймворки позволяют использовать FIndObjects с помощью строк, а код может выглядеть так: FindObject («ObjectName»);

119
задан Peter Mortensen 6 April 2011 в 10:33
поделиться

14 ответов

Начнем с retain и release; autorelease - это действительно особый случай, когда вы понимаете основные понятия.

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

Основной способ отличается от malloc и free тем, что любой заданный объект не нужно беспокоиться о сбоях других частей системы, потому что вы освободили память, которую они использовали. Предполагая, что все играют и сохраняют / освобождают в соответствии с правилами, когда одна часть кода сохраняет и затем освобождает объект, любая другая часть кода, также ссылающаяся на объект, не будет затронута.

Что иногда может быть смущает знание обстоятельств, при которых вы должны называть retain и release. Мое общее правило состоит в том, что если я хочу некоторое время зависать с объектом (если это переменная-член в классе), то мне нужно убедиться, что счетчик ссылок объекта знает обо мне. Как описано выше, счетчик ссылок объекта увеличивается, вызывая retain. По соглашению, он также увеличивается (устанавливается на 1, действительно), когда объект создается с помощью метода «init». В любом из этих случаев моя обязанность называть release объектом, когда я закончил с этим. Если я этого не сделаю, произойдет утечка памяти.

Пример создания объекта:

NSString* s = [[NSString alloc] init];  // Ref count is 1
[s retain];                             // Ref count is 2 - silly
                                        //   to do this after init
[s release];                            // Ref count is back to 1
[s release];                            // Ref count is 0, object is freed

Теперь для autorelease. Автореферат используется как удобный (а иногда и необходимый) способ сообщить системе, чтобы освободить этот объект через некоторое время. С точки зрения водопровода, когда вызывается autorelease, текущий поток NSAutoreleasePool предупреждается о вызове. NSAutoreleasePool теперь знает, что как только он получит возможность (после текущей итерации цикла событий), он может вызвать release на объекте. С нашей точки зрения, как программисты, он заботится о том, чтобы называть нас release, поэтому нам не нужно (и на самом деле мы не должны).

Важно отметить, что (снова , по соглашению) все методы создания объекта class возвращают автореализованный объект. Например, в следующем примере переменная «s» имеет счетчик ссылок 1, но после того, как цикл цикла завершен, он будет уничтожен.

NSString* s = [NSString stringWithString:@"Hello World"];

Если вы хотите висеть на этой строке , вам нужно будет явно вызвать retain, а затем явно release, когда вы закончите.

Рассмотрим следующий (очень надуманный) бит кода, и вы увидите ситуацию где требуется autorelease:

- (NSString*)createHelloWorldString
{
    NSString* s = [[NSString alloc] initWithString:@"Hello World"];

    // Now what?  We want to return s, but we've upped its reference count.
    // The caller shouldn't be responsible for releasing it, since we're the
    // ones that created it.  If we call release, however, the reference 
    // count will hit zero and bad memory will be returned to the caller.  
    // The answer is to call autorelease before returning the string.  By 
    // explicitly calling autorelease, we pass the responsibility for
    // releasing the string on to the thread's NSAutoreleasePool, which will
    // happen at some later time.  The consequence is that the returned string 
    // will still be valid for the caller of this function.
    return [s autorelease];
}

Я понимаю, что все это немного запутанно - в какой-то момент, однако, он щелкнет. Вот несколько ссылок, которые помогут вам:

  • Введение в Apple для управления памятью.
  • Программирование какао для Mac OS X ( 4-е издание) , автор Aaron Hillegas - очень хорошо написанная книга с множеством замечательных примеров. Это читается как учебник.
  • Если вы действительно погружаетесь, вы можете отправиться в Big Nerd Ranch . Это учебное заведение, которое ведет Аарон Хильгамас - автор книги, упомянутой выше. Несколько лет назад я посещал курс Intro to Cocoa, и это был отличный способ узнать.
148
ответ дан Matt Dillard 31 August 2018 в 23:52
поделиться

Как уже упоминалось уже несколько людей, для Apple - лучшее место для запуска.

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

0
ответ дан Brian Moeskau 31 August 2018 в 23:52
поделиться

Много хорошей информации о кокодаде тоже:

1
ответ дан charles 31 August 2018 в 23:52
поделиться

Если вы пишете код для рабочего стола, и вы можете настроить таргетинг на Mac OS X 10.5, вам следует, по крайней мере, изучить использование сборки мусора Objective-C. Это действительно упростит большую часть вашего развития - вот почему Apple приложила все усилия к его созданию в первую очередь и сделала его хорошо.

Что касается правил управления памятью, когда не используется GC:

  • Если вы создаете новый объект, используя +alloc/+allocWithZone:, +new, -copy или -mutableCopy, или если вы -retain объект, вы берете его на себя и должны убедиться, что он отправлено -release.
  • Если вы получаете объект каким-либо другим способом, вы не владеете им и не должны not гарантировать его отправку -release.
  • Если вы хотите удостовериться, что объект отправлен -release, вы можете отправить его самостоятельно, или вы можете отправить объект -autorelease и текущий пул автономии отправит его -release (один раз на прием -autorelease), когда пул слит.

Обычно -autorelease используется как способ обеспечения того, чтобы объекты находились на длине текущего события, но затем очищаются, так как есть пул авторезистов, который окружает обработку событий Cocoa. В Cocoa это far более распространено, чтобы возвращать объекты вызывающему, которые автореализованы, чем возвращать объекты, которые сам вызывающий должен освободить.

8
ответ дан Chris Hanson 31 August 2018 в 23:52
поделиться

Matt Dillard написал :

return [[s autorelease] release];

Autorelease делает not сохранить объект. Autorelease просто помещает его в очередь для выпуска позже. Вы не хотите иметь там релиз.

5
ответ дан Community 31 August 2018 в 23:52
поделиться

В приведенных выше ответах дается четкое подтверждение того, что говорится в документации; проблема, с которой сталкиваются самые новые люди, - это недокументированные случаи. Например:

  • Autorelease: docs заявляют, что он выведет релиз «в какой-то момент в будущем». КОГДА?! В принципе, вы можете рассчитывать на объект, находящийся вокруг, пока вы не вернете свой код обратно в цикл системных событий. Система МОЖЕТ освободить объект в любое время после текущего цикла событий. (Я думаю, что Мэтт сказал это раньше).
  • Статические строки: NSString *foo = @"bar"; - вам нужно сохранить или отпустить это? Нет. Как насчет
    -(void)getBar {
        return @"bar";
    }
    
    ...
    NSString *foo = [self getBar]; // still no need to retain or release
    
  • Правило создания: если вы создали его, вы его обладаете и, как ожидается, его освободите.

В общем, способ, которым программисты Cocoa запутались, не понимает, какие подпрограммы возвращают объект с помощью retainCount > 0.

Вот фрагмент из Очень простые правила для управления памятью в какао :

Правила счета удержания

  • Внутри данного блока использование -copy, -alloc и - сохранение должно быть равно использованию -release и -autorelease.
  • Объекты, созданные с использованием конструкторов удобства (например, stringWithString для NSString), считаются автореализованными.
  • Внедрить метод -dealloc для освобождения экземпляров переменных own

1-я марка говорит: если вы вызвали alloc (или new fooCopy), вам нужно вызвать release на этом объекте.

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

Третий должен быть понятным.

2
ответ дан Jason Plank 31 August 2018 в 23:52
поделиться

Joshua (# 6591) - Сборник мусора в Mac OS X 10.5 выглядит довольно круто, но недоступен для iPhone (или если вы хотите, чтобы ваше приложение запускалось на версиях Mac OS X до 10.5).

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

6
ответ дан Matt Sheppard 31 August 2018 в 23:52
поделиться

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

Apple предоставляет полное описание системы управления памятью Cocoa в Руководство по программированию управления памятью для Cocoa , в конце которого имеется краткое, но точное резюме правил управления памятью .

6
ответ дан mmalc 31 August 2018 в 23:52
поделиться

Моя обычная коллекция статей управления памятью какао:

Управление памятью какао

5
ответ дан NANNAV 31 August 2018 в 23:52
поделиться

Objective-C использует подсчет ссылок , что означает, что каждый объект имеет счетчик ссылок. Когда объект создается, он имеет счетчик ссылок «1». Проще говоря, когда объект ссылается (т. Е. Где-то где-то), он получает «сохраненный», что означает, что его счетчик ссылок увеличивается на единицу. Когда объект больше не нужен, он «освобождается», что означает, что его количество ссылок уменьшается на единицу.

Когда счетчик ссылок объекта равен 0, объект освобождается. Это основной подсчет ссылок.

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

Типичным способом написания метода является:

id myVar = [someObject someMessage];
.... do something ....;
[myVar release];
return someValue;

Проблема необходимости запоминать любые приобретенные ресурсы внутри кода является утомительным и подверженным ошибкам. Objective-C вводит еще одну концепцию, направленную на то, чтобы сделать это намного проще: Autorelease Pools. Пулы Autorelease - это специальные объекты, которые устанавливаются в каждом потоке. Это довольно простой класс, если вы посмотрите NSAutoreleasePool.

Когда объект получает сообщение «autorelease», отправленное ему, объект будет искать любые пулы автозаполнения, которые находятся в стеке для этого текущего потока. Он добавит объект в список в качестве объекта для отправки сообщения «release» в какой-то момент в будущем, что обычно происходит при выпуске самого пула.

. Принимая код выше, вы можете переписывайте его, чтобы быть короче и легче читать, говоря:

id myVar = [[someObject someMessage] autorelease];
... do something ...;
return someValue;

Поскольку объект автореализован, нам больше не нужно явно вызывать «release» на нем. Это связано с тем, что мы знаем, что некоторый пул авторесурсов сделает это для нас позже.

Надеюсь, это поможет. Статья в Википедии довольно хороша в подсчете ссылок. Более подробную информацию о пулах autorelease можно найти здесь . Также обратите внимание, что если вы создаете Mac OS X 10.5 и более поздние версии, вы можете сказать, что Xcode для сборки с включенной сборкой мусора позволяет полностью игнорировать сохранение / освобождение / автоопределение.

6
ответ дан NilObject 31 August 2018 в 23:52
поделиться

Я не буду добавлять к конкретному сохранению / выпуску, кроме того, что вы можете подумать о том, чтобы сбросить 50 долларов и получить книгу Hillegass, но я настоятельно рекомендую вначале использовать инструменты инструментов очень рано в разработке вашего приложения (даже ваш первый!). Для этого выполните Run-> Start с инструментами производительности. Я бы начал с Leaks, который является лишь одним из многих доступных инструментов, но поможет вам показать, когда вы забыли освободить. Это прекрасная информация о том, сколько информации вам будет представлено. Но посмотрите этот учебник, чтобы встать и идти быстро: COCOA TUTORIAL: FIXING MEMORY LEAKS WITH INSTRUMENTS

На самом деле попытка утечки force может быть лучше способ, в свою очередь, научиться предупреждать их! Удачи;)

6
ответ дан Rob 31 August 2018 в 23:52
поделиться

Ответ NilObject - хорошее начало. Ниже приведена дополнительная информация, относящаяся к ручному управлению памятью (, требуемая на iPhone ).

Если вы лично alloc/init объект, он содержит счетчик ссылок 1. Вы ответственный за очистку после него, когда он больше не нужен, либо путем вызова [foo release], либо [foo autorelease]. релиз очищает его сразу, в то время как autorelease добавляет объект в пул авторесурсов, который автоматически освободит его позже.

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

Если вы приобрели объект, в котором вы не вызывали alloc / init, чтобы его получить - например:

foo = [NSString stringWithString:@"hello"];

, но вы хотите висеть на этом объекте, вам нужно вызвать [foo сохранить]. В противном случае, возможно, он получит autoreleased, и вы будете держаться за нулевую ссылку (как это было бы в примере выше stringWithString ). Когда вам это больше не нужно, вызовите [foo release].

4
ответ дан Sangram S. 31 August 2018 в 23:52
поделиться

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

  1. Если функция, которая возвращает объект, имеет alloc, create или copy в своем имени, тогда объект принадлежит вам. Вы должны позвонить [object release], когда закончите с ним. Или CFRelease(object), если это объект Core-Foundation.
  2. Если у него нет ни одного из этих слов в его имени, то объект принадлежит кому-то другому. Вы должны называть [object retain], если вы хотите сохранить объект после окончания вашей функции.

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

(Nitpickers: Да, есть, к сожалению, несколько вызовов API, которые являются исключениями из этих правил, но они редки).

10
ответ дан Unheilig 31 August 2018 в 23:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: