What kind of leaks does automatic reference counting in Objective-C not prevent or minimize?
Solution 1:
The primary memory-related problem you'll still need to be aware of is retain cycles. This occurs when one object has a strong pointer to another, but the target object has a strong pointer back to the original. Even when all other references to these objects are removed, they still will hold on to one another and will not be released. This can also happen indirectly, by a chain of objects that might have the last one in the chain referring back to an earlier object.
It is for this reason that the __unsafe_unretained
and __weak
ownership qualifiers exist. The former will not retain any object it points to, but leaves open the possibility of that object going away and it pointing to bad memory, whereas the latter doesn't retain the object and automatically sets itself to nil when its target is deallocated. Of the two, __weak
is generally preferred on platforms that support it.
You would use these qualifiers for things like delegates, where you don't want the object to retain its delegate and potentially lead to a cycle.
Another couple of significant memory-related concerns are the handling of Core Foundation objects and memory allocated using malloc()
for types like char*
. ARC does not manage these types, only Objective-C objects, so you'll still need to deal with them yourself. Core Foundation types can be particularly tricky, because sometimes they need to be bridged across to matching Objective-C objects, and vice versa. This means that control needs to be transferred back and forth from ARC when bridging between CF types and Objective-C. Some keywords related to this bridging have been added, and Mike Ash has a great description of various bridging cases in his lengthy ARC writeup.
In addition to this, there are several other less frequent, but still potentially problematic cases, which the published specification goes into in detail.
Much of the new behavior, based on keeping objects around as long as there is a strong pointer to them, is very similar to garbage collection on the Mac. However, the technical underpinnings are very different. Rather than having a garbage collector process that runs at regular intervals to clean up objects no longer being pointed to, this style of memory management relies on the rigid retain / release rules we all need to obey in Objective-C.
ARC simply takes the repetitive memory management tasks we've had to do for years and offloads them to the compiler so we never have to worry about them again. This way, you don't have the halting problems or sawtooth memory profiles experienced on garbage collected platforms. I've experienced both of these in my garbage collected Mac applications, and am eager to see how they behave under ARC.
For more on garbage collection vs. ARC, see this very interesting response by Chris Lattner on the Objective-C mailing list, where he lists many advantages of ARC over Objective-C 2.0 garbage collection. I've run into several of the GC issues he describes.
Solution 2:
ARC won't help you with non-ObjC memory, for example if you malloc()
something, you still need to free()
it.
ARC can be fooled by performSelector:
if the compiler can't figure out what the selector is (the compiler will generate a warning on that).
ARC will also generate code following ObjC naming conventions, so if you mix ARC and MRC code you can get surprising results if the MRC code doesn't do what the compiler thinks the names promise.
Solution 3:
I experienced memory leaks in my application due the following 4 issues:
- Not invalidating NSTimers when dismissing view controllers
- Forgetting to remove any observers to NSNotificationCenter when dismissing the view controller.
- Keeping strong references to self in blocks.
- Using strong references to delegates in view controller properties
Luckily I came across the following blog post and was able to correct them: http://www.reigndesign.com/blog/debugging-retain-cycles-in-objective-c-four-likely-culprits/