Глубокое понимание цикла сохранения

Допустим, у нас есть три объекта: бабушка и дедушка, родитель и ребенок. Прадедушка оставляет за собой родителя, родитель сохраняет ребенка, а ребенок сохраняет родителя. Бабушка и дедушка отпускают родителя.

Что будет в этом случае?


person Tariq    schedule 10.11.2013    source источник


Ответы (10)


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

Ребенок никогда не должен оставлять себе родителей. Во всяком случае, используйте слабую ссылку в дочернем элементе, чтобы поддерживать ссылку на родителя.

person rmaddy    schedule 10.11.2013
comment
Просто хотел добавить, что в некоторых редких случаях может быть полезно, чтобы дочерний элемент сохранял родителя, вам просто нужно добавить метод, который в какой-то момент разорвет цикл (и гарантирует, что он будет вызываться, когда объекты должны быть убрано). - person Taum; 18.04.2014
comment
@Taum Когда ребенку нужно оставить родителя? Слабая ссылка на родителя - это нормально, но почему сильная ссылка? - person rmaddy; 18.04.2014
comment
@rmaddy, возможно, что-то, в чем вы отключили запуск анимации или другого действия, основанного на таймере, и больше не владеете им. Вы бы хотели, чтобы он оставался там столько, сколько нужно, и убирался за собой. - person Zev Eisenberg; 26.04.2014

Цикл сохранения - это условие. Когда 2 объекта сохраняют ссылку друг на друга и сохраняются, он создает цикл сохранения, поскольку оба объекта пытаются сохранить друг друга, что делает невозможным освобождение.

Здесь «бабушка и дедушка» сохраняет «родителя», а «родитель» сохраняет «дочерний элемент», тогда как «дочерний элемент» сохраняет «родителя». Здесь устанавливается цикл сохранения между родителем и дочерним элементом. После освобождения бабушки и дедушки и родитель, и потомок становятся сиротами, но счетчик удержания родителя не будет равен нулю, так как он сохраняется дочерним и, следовательно, вызывает проблему с управлением памятью.

Есть два возможных решения:

1) Используйте слабый указатель на родителя, т.е. дочерний элемент должен использовать слабую ссылку на родителя, которая не сохраняется.

2) Используйте методы «закрытия», чтобы разорвать циклы сохранения.

http://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html

person Aritra Das    schedule 10.11.2013

В простом случае рассмотрим два объекта A и B, где A создает и сохраняет B. Когда A создается, он создает B. Когда тот, кто создал A, наконец, освобождает его, счетчик сохранения A падает до нуля, и он освобождается. Если метод dealloc A вызывает release для B, счетчик сохранения B также падает до нуля, и он также освобождается. [Это предполагает, что никто другой не сохранил A или B, потому что я упрощаю.]

Но что произойдет, если B потребуется обратная ссылка на A, и он сохранит A? Кто бы ни создал A, может выпустить его. Но поскольку B также сохранил A, счетчик удержания A не станет равным нулю. Точно так же, поскольку A сохраняет B, счетчик удержания B также не обнуляется. Ни то, ни другое не будет освобождено. Даже если B вызывает метод выпуска A в своем собственном освобождении, это не имеет значения, потому что этот метод никогда не будет вызван.

На этом этапе у вас есть утечка памяти, потому что у вас нет ссылки на A или B, хотя они оба все еще существуют. Если A или B что-то интенсивно используют для процессора, вы также можете терять процессорное время для нежелательных объектов.

В вашем случае A - родитель, а B - ребенок, и тот, кто создал A, является дедушкой или бабушкой.

person RMDeveloper    schedule 10.08.2015

Цикл сохранения - это цикл, который происходит, когда объект A сохраняет объект B, а объект B сохраняет объект A. В этой ситуации, если один из объектов освобожден:

  • Объект A не будет освобожден, потому что объект B содержит ссылку на него (сохранить счетчик> 0).
  • Объект B никогда не будет освобожден, пока объект A имеет ссылку на него (сохранить счетчик> 0).
  • Но объект A никогда не будет освобожден, потому что объект B содержит ссылку на него (сохранить счетчик> 0).
  • до бесконечности

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

person Aamir    schedule 26.06.2016
comment
@Balasubramanian: мы сохраняем слабую ссылку в любом объекте, в зависимости от того, какой объект владеет другим объектом, владелец должен сохранять сильную ссылку, а другую - слабую. - person Aamir; 22.10.2017

Когда дедушка и бабушка освобождают родителя, родитель все еще жив, поскольку ребенок сохраняет родителя.

person Danyun Liu    schedule 10.11.2013

Дедушка: Джон Родитель: Тед Ребенок: Мэри

Вот мой пример использования телефонного звонка для иллюстрации:

  • Джон звонит Теду и хочет провести конференц-связь с Мэри.

  • Тед говорит Джону: «Подожди, я позвоню Мэри»

  • Тед оставляет Джона на удержании и звонит Мэри, которая сразу же отвечает на звонок.

  • Мэри говорит Теду: «Соедините мой звонок с Джоном, и я НЕ буду вешать трубку, пока не закончу»

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

  • Джон идет объединить звонки с Тедом и Мэри, а затем внезапно умирает.

  • Мэри застряла на линии с Джоном, но никогда не повесит трубку, потому что Джон не вернется!

person paul_f    schedule 22.01.2019

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


Пример: человек живет в отделе, в отделе один человек.

@class Department;

@interface Person:NSObject
@property (strong,nonatomic)Department * department;
@end

@implementation Person
-(void)dealloc{
    NSLog(@"dealloc person");
}

@end
@interface Department: NSObject
@property (strong,nonatomic)Person * person;
@end

@implementation Department
-(void)dealloc{
    NSLog(@"dealloc Department");
}
@end

Тогда назовите это так:

- (void)viewDidLoad {
    [super viewDidLoad];
    Person * person = [[Person alloc] init];
    Department * department = [[Department alloc] init];
    person.department = department;
    department.person = person;
}

Вы не увидите журнал освобождения, это круг сохранения.

person delarcomarta    schedule 23.10.2017

Так как объект P имеет значение keepCount, равное 1, когда он освобождается, его значение keepCount становится равным 0, и вызывается его метод dealloc; Это, в свою очередь, вызывает освобождение объекта C, счетчик удержания которого также становится равным 0; и вызывается его метод dealloc.

Оба объекта P и C будут освобождены.

Когда вызывается метод dealloc объекта C, в свою очередь вызывается освобождение объекта GP, но, поскольку GP содержит счетчик сохранения, равный 2, счетчик сохранения уменьшается до 1 и продолжает оставаться.

person Shalab    schedule 18.04.2014
comment
P имеет значение keepCount равное 2 до того, как оно будет выпущено GP (оно сохраняется GP и C). - person Taum; 18.04.2014
comment
Ты прав. Прочтите исходный вопрос немного иначе и неправильно - :). Я прочитал вопрос, как gp- ›p-› c- ›gp keep cycle вместо gp-› p- ›c-› p cycle. - person Shalab; 18.04.2014

Цикл сохранения - это состояние тупика. Реальный пример цикла сохранения: если два объекта содержат ссылку друг на друга, и никакой другой объект не освобождается.

Пример: Рамми-игра

person Saurabh Sharma    schedule 19.02.2019

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

person Talha Rasool    schedule 04.03.2020