Retain Cycles: почему это так плохо? - PullRequest
10 голосов
/ 26 апреля 2009

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

Но так ли это на самом деле?

Если B выпустит A, то A может легко освободить B, и поэтому B будет освобожден. A будет освобожден, как только его освободит другой владелец (наверное, кто-то).

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

Ответы [ 4 ]

15 голосов
/ 26 апреля 2009

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

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

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

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

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

Некоторые языки с сборщиком мусора (например, C #) могут удалять группу объектов, которые больше не нужны, даже если в группе есть циклы.

7 голосов
/ 26 апреля 2009

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

A* a = [[A alloc] initAndCreateB];

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

Допустим, мы закончили с использованием A:

[a release];
return 12;

Теперь счет сохранения А равен 1. Он не будет освобожден, его память потеряна. Вот почему сохранять циклы плохо.

3 голосов
/ 27 апреля 2009

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

т.е.

A retains B
B retains A

когда вы закончите, вызовите метод (я назову его "close") для A, где A освобождает B. Затем вы можете освободить A, и весь цикл будет освобожден (при условии, что в другом месте нет задержек) .

2 голосов
/ 26 апреля 2009

Проблема заключается в следующем: A указывает и сохраняет B, а B указывает и сохраняет A. Когда нет других ссылок на A или B, не будет никакого способа освободить их, потому что ваше приложение не имеет любые ссылки на них в этот момент. Это называется ссылочным циклом, и это тип утечки памяти, распространенный в любой системе с подсчетом ссылок. Для решения этой проблемы в большинстве языков высокого уровня используется сборка мусора, а не подсчет ссылок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...