Obj-C Управление памятью
Управление памятью - один из самых важных процессов в любом языке программирования. Это процесс, при котором память объектов выделяется, когда они требуются, и освобождается, когда они больше не нужны.
Управление памятью объектов - это вопрос производительности; если приложение не освобождает ненужные объекты, объем его памяти увеличивается, а производительность снижается.
Методы управления памятью в Objective-C можно разделить на два типа.
- «Ручное удержание-выпуск» или MRR
- «Автоматический подсчет ссылок» или ARC
«Ручное удержание-выпуск» или MRR
В MRR мы явно управляем памятью, отслеживая объекты самостоятельно. Это реализовано с использованием модели, известной как подсчет ссылок, которую класс Foundation NSObject предоставляет вместе со средой выполнения.
Единственная разница между MRR и ARC заключается в том, что в первом случае сохранение и освобождение обрабатываются вручную, а во втором - автоматически.
На следующем рисунке представлен пример того, как управление памятью работает в 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».
Мы можем стать владельцем объекта, используя функцию сохранения: обычно гарантируется, что полученный объект останется действительным в рамках метода, в котором он был получен, и этот метод также может безопасно возвращать объект его вызывающей стороне. Мы используем сохранение в двух ситуациях -
В реализации метода доступа или метода инициализации, чтобы стать владельцем объекта, который мы хотим сохранить как значение свойства.
Чтобы объект не стал недействительным как побочный эффект какой-либо другой операции.
Когда он нам больше не нужен, мы должны отказаться от владения объектом, которым мы владеем: мы отказываемся от владения объектом, отправив ему сообщение о выпуске или сообщение об автозапуске. Поэтому в терминологии Какао отказ от владения объектом обычно называется «освобождением» объекта.
Вы не должны отказываться от владения объектом, которым вы не владеете: это просто следствие предыдущих правил политики, сформулированных явно.
#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 нам не нужно добавлять методы выпуска и сохранения, так как об этом позаботится компилятор. На самом деле, процесс, лежащий в основе 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;
}
Когда мы скомпилируем вышеуказанную программу, мы получим следующий результат.
2013-09-28 04:45:47.310 demo[8385] Hello, World!
2013-09-28 04:45:47.311 demo[8385] Object deallocated