简体   繁体   中英

Retain Cycles: Why is that such a bad thing?

There are two Objects A and B. A creates B and retains it. B has an instance variable that points to A, retaining it. So both retain eachother. Some people say, that this strong connection can't be broken ever again.

But is that really the case?

If B would release A, then A could easily release B, and so B would be deallocated. A would be deallocated as soon as it's other owner (I guess there must be someone) releases it.

Or does this problem only apply in a case where A does not create B, but just holds a strong reference to it through retaining it in an instance variable? I still don't see why that connection could not be broken up again.

Cycles aren't bad, but they are often avoided because they can make it tricky to ensure you haven't got memory leaks. Leaks occur especially when objects are 'reference counted'. In a language or system that uses reference counting, an object keeps track of the number of references pointing at it. Every time a reference is deleted, the count goes down, when the count gets to zero, there are no references and so the object can be deleted.

This usually takes care of itself and works ok without any careful thinking. If you've got a group of objects with no cycles and you drop your reference to the root object, then it will be deleted, this means references it has to objects it owns will be dropped, the objects being referenced will have their reference counts go to zero. They'll be deleted and the cascade will cause all objects to be deleted.

But... if you have a cycle, this cascade doesn't work. You may have a group of objects and you don't want them any more, so you drop the only reference you have to these objects, but because there is a cycle the objects reference each other. This means their reference counts never go to zero, and they don't get deleted. This is a memory leak.

Clearly, you can do some careful management and break the cycles before you drop your reference to a group of objects you don't want any more. But... as I just said, this takes careful management. It's very easy to get wrong. This is one of the main reasons that memory leaks occur.

To avoid the risk of leaks and the tricky job of breaking cycles correctly when you no longer need a group of objects, programmers usually try to avoid cycles. This becomes more important on big projects with many programmers where no one person understands the whole system. If there were cycles, the programmers would have to watch out and spend a long time studying each others code to avoid cycles.

Some languages with garbage collectors (eg C#) can delete a group of objects that are no longer needed even if the group contains cycles.

A retain cycle can be broken, if you know about it. Usually it leads to nasty bugs (memory leaks). In your example:

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

Now, a unnamed B instance (created by A) has a retain count of 1. Since we hold a reference to A and the anonymous B instance holds a strong reference to A, A's retain count is 2.

Let's say, we are done using A:

[a release];
return 12;

Now, A's retain count is 1. It will not be released, it's memory is lost. That's why retain cycles are bad.

The way to break a retain loop is to have a separate "close" method.

ie

A retains B
B retains A

when you're done, call a method (I'll call it " close ") on A where A releases B. You can then release A and the whole loop will release (assuming there are no retains elsewhere).

The problem is this: A points to and retains B, and B points to and retains A. When there are no other references to A or B, there will be no way to release them, because you app doesn't have any references to them at that point. This is called a reference cycle, and it a type of memory leak common in any reference counted system. The way this is solved in most high level languages is by using garbage collection rather than reference counting.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM