Учебники

Управление памятью Obj-C

Управление памятью является одним из наиболее важных процессов в любом языке программирования. Это процесс, посредством которого память объектов выделяется, когда они требуются, и освобождается, когда они больше не требуются.

Управление памятью объекта — это вопрос производительности; если приложение не освобождает ненужные объекты, его объем памяти увеличивается, а производительность снижается.

Objective-C Методы управления памятью можно разделить на два типа.

  • «Ручное удержание-отпускание» или MRR
  • «Автоматический подсчет ссылок» или ARC

«Ручное удержание-отпускание» или MRR

В MRR мы явно управляем памятью, отслеживая объекты самостоятельно. Это реализовано с использованием модели, известной как подсчет ссылок, которую NSObject класса Foundation предоставляет в сочетании со средой выполнения.

Единственная разница между MRR и ARC заключается в том, что удержание и разблокирование обрабатываются нами вручную в первом, а в последнем автоматически.

На следующем рисунке представлен пример того, как работает управление памятью в Objective-C.

Objective-C Управление памятью

Жизненный цикл памяти объекта класса A показан на рисунке выше. Как вы можете видеть, счет сохранения отображается под объектом, когда счет сохранения объекта становится равным 0, объект полностью освобождается, и его память освобождается для использования другими объектами.

Объект класса A сначала создается с использованием метода alloc / init, доступного в NSObject. Теперь счет удержания становится 1.

Теперь класс B сохраняет объект класса A, а количество сохраняемых объектов класса A становится равным 2.

Затем класс C делает копию объекта. Теперь он создается как еще один экземпляр класса A с такими же значениями для переменных экземпляра. Здесь счет сохранения равен 1, а не счет хранения исходного объекта. Это представлено пунктирной линией на рисунке.

Скопированный объект высвобождается классом C с использованием метода release, и счет сохранения становится равным 0, и, следовательно, объект уничтожается.

В случае начального объекта класса A, счет удержания равен 2, и его необходимо дважды разблокировать, чтобы уничтожить. Это делается с помощью инструкций выпуска класса A и класса B, которые уменьшают количество сохраняемых данных до 1 и 0 соответственно. Наконец, объект уничтожен.

Основные правила MRR

  • У нас есть любой объект, который мы создаем: мы создаем объект, используя метод, имя которого начинается с «alloc», «new», «copy» или «mutableCopy»

  • Мы можем вступить во владение объектом, используя retain: полученный объект обычно гарантированно остается действительным в методе, в котором он был получен, и этот метод также может безопасно вернуть объект своему вызывающему. Мы используем удержание в двух ситуациях —

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

    • Для предотвращения признания объекта недействительным в качестве побочного эффекта какой-либо другой операции.

  • Когда он нам больше не нужен, мы должны отказаться от права собственности на принадлежащий нам объект: мы отказываемся от права собственности на объект, отправив ему сообщение о выпуске или сообщение об автоматическом выпуске. Таким образом, в терминологии какао отказ от владения объектом обычно называется «высвобождением» объекта.

  • Вы не должны отказываться от владения объектом, который вам не принадлежит: это всего лишь следствие предыдущих правил политики, установленных в явном виде.

У нас есть любой объект, который мы создаем: мы создаем объект, используя метод, имя которого начинается с «alloc», «new», «copy» или «mutableCopy»

Мы можем вступить во владение объектом, используя retain: полученный объект обычно гарантированно остается действительным в методе, в котором он был получен, и этот метод также может безопасно вернуть объект своему вызывающему. Мы используем удержание в двух ситуациях —

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

Для предотвращения признания объекта недействительным в качестве побочного эффекта какой-либо другой операции.

Когда он нам больше не нужен, мы должны отказаться от права собственности на принадлежащий нам объект: мы отказываемся от права собственности на объект, отправив ему сообщение о выпуске или сообщение об автоматическом выпуске. Таким образом, в терминологии какао отказ от владения объектом обычно называется «высвобождением» объекта.

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

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
- (void)sampleMethod;
@end

@implementation SampleClass
- (void)sampleMethod {
   NSLog(@"Hello, World! \n");
}

- (void)dealloc  {
  NSLog(@"Object deallocated");
  [super dealloc];
}

@end

int main() {
   
   /* my first program in Objective-C */
   SampleClass *sampleClass = [[SampleClass alloc]init];
   [sampleClass sampleMethod];
   
   NSLog(@"Retain Count after initial allocation: %d", 
   [sampleClass retainCount]);
   [sampleClass retain];
   
   NSLog(@"Retain Count after retain: %d", [sampleClass retainCount]);
   [sampleClass release];
   NSLog(@"Retain Count after release: %d", [sampleClass retainCount]);
   [sampleClass release];
   NSLog(@"SampleClass dealloc will be called before this");
   
   // Should set the object to nil
   sampleClass = nil;
   return 0;
}

Когда мы скомпилируем вышеуказанную программу, мы получим следующий вывод.

2013-09-28 04:39:52.310 demo[8385] Hello, World!
2013-09-28 04:39:52.311 demo[8385] Retain Count after initial allocation: 1
2013-09-28 04:39:52.311 demo[8385] Retain Count after retain: 2
2013-09-28 04:39:52.311 demo[8385] Retain Count after release: 1
2013-09-28 04:39:52.311 demo[8385] Object deallocated
2013-09-28 04:39:52.311 demo[8385] SampleClass dealloc will be called before this

«Автоматический подсчет ссылок» или ARC

В автоматическом подсчете ссылок или ARC система использует ту же систему подсчета ссылок, что и MRR, но она вставляет соответствующие вызовы метода управления памятью для нас во время компиляции. Мы настоятельно рекомендуем использовать ARC для новых проектов. Если мы используем ARC, обычно нет необходимости понимать основную реализацию, описанную в этом документе, хотя в некоторых ситуациях это может быть полезно. Для получения дополнительной информации о ARC см. Переход к примечаниям к выпуску ARC.

Как уже упоминалось выше, в ARC нам не нужно добавлять методы release и retain, поскольку об этом позаботится компилятор. На самом деле, основной процесс Objective-C все тот же. Он использует операции сохранения и выпуска для внутреннего использования, что облегчает разработчику кодирование, не беспокоясь об этих операциях, что уменьшит как объем написанного кода, так и возможность утечек памяти.

Был еще один принцип, называемый сборкой мусора, который используется в Mac OS-X вместе с MRR, но с момента его устаревания в OS-X Mountain Lion он не обсуждался вместе с MRR. Кроме того, объекты iOS никогда не имели функции сборки мусора. А с ARC также нет необходимости в сборке мусора в OS-X.

Вот простой пример ARC. Обратите внимание, что это не будет работать на онлайн-компиляторе, так как он не поддерживает ARC.

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
- (void)sampleMethod;
@end

@implementation SampleClass
- (void)sampleMethod {
   NSLog(@"Hello, World! \n");
}

- (void)dealloc  {
  NSLog(@"Object deallocated");
}

@end

int main() {
   /* my first program in Objective-C */
   @autoreleasepool {
      SampleClass *sampleClass = [[SampleClass alloc]init];
      [sampleClass sampleMethod];
      sampleClass = nil;
   }
   return 0;
}

Когда мы скомпилируем вышеуказанную программу, мы получим следующий вывод.