Structure and Interpretation of Computer Programmers

I make it easier and faster for you to write high-quality software.

Monday, December 22, 2008

Cocoa Memory Management

It becomes evident, thanks to the mass centralisation of the neverending september effect that is stackoverflow, that despite the large number of electrons expended on documenting the retain/release/autorelease reference counting mechanism for managing memory in Cocoa, Cocoa Touch, UIKit, AppKit, Foundation, GNUstep, Cocotron and Objective-C code, very few people are reading that. My purpose in this post is not to re-state anything which has already been said. My purpose is to aggregate information I’ve found on the topic of managing memory in Cocoa, so I can quote this post in answers to questions like these.

In fact, I’ve already answered this question myself, as How does reference counting work? As mentioned in the FAQ, I actually answered the question “how do I manage object lifecycles in (Cocoa|GNUstep|Cocotron)”? It’s actually a very violently distilled discussion, so it’s definitely worth checking out the references (sorry) below.

Apple have a very good, and complete, Memory Management Programming Guide for Cocoa. They also provide a Garbage Collection Programming Guide; remember that Objective-C garbage collection is opt-in on 10.5 and above (and unavailable on iPhone OS or earlier versions of Mac OS X). GNUsteppers reading along should remember that the garbage collector available with the GNU objc runtime is entirely unlike the collector documented in Apple’s guide. GNUstep documentation contains a similar guide to memory management, as well as going into more depth about memory allocation and zones. Apple will also tell you how objects in NIBs are managed.

The article which gave me my personal eureka moment was Hold Me, Use Me, Free Me by Don Yacktman. Stepwise has another article, very simple rules for memory management in Cocoa by mmalc, which is a good introduction though with one caveat. While the table of memory management methods at the top of the article are indeed accurate, they might give you the impression that keeping track of the retain count is what you’re supposed to be doing. It’s not :). What you’re supposed to be doing is balancing your own use of the methods for any given object, as described in rules 1 and 2 of “Retention Count rules” just below that table.

James Duncan Davidson’s book “Learning Cocoa with Objective-C” has not been updated in donkey’s years, but its section on memory management is quite good, especially the diagrams and the “rules of thumb” summary. Luckily, that section on memory management is the free sample on O’Reilly’s website.

If reading the theoretical stuff is all a bit too dry, the Mac Developer Network have a rather comprehensive memory management training video which is $9.99 for non-MDN members and free for paid-up members.

Finally, Chris Hanson has written a good article on interactions between Cocoa memory management and objc-exceptions; if you’re using exceptions this is a good discussion of the caveats you might meet.

posted by Graham Lee at 13:34  

Tuesday, June 24, 2008

Objective-C NAQs

Never-Asked Questions :-)

In Code Complete 2 §6.5, Steve McConnell presents a list of class-related design issues that "vary significantly depending on the language". So why don’t we look at them for Objective-C? Especially as I can’t find anyone else who’s done so based on a couple of Google searches… N.B. as ever, I’m really considering Cocoa + Objective-C here, as the language itself doesn’t provide enough policy for many of the issues to have an answer (only method resolution and the existence of isa are defined by the runtime and the compiler – ignoring details like static string instances, @protocol and so on).

Behaviour of overridden constructors and destructors in an inheritance tree. Constructors are simple. If you can initialise an object, return it. If you can’t, return nil. The -[NSObject init] method is documented as simply returning self.

For destructors, we have to split the discussion into twain; half for garbage collection and half for not. In the world of the Apple GC, destruction is best done automatically, but if you need to do any explicit cleanup then your object implements -finalize. The two rules are that you don’t know whether other objects have already been finalized or not, and that you must not resurrect your object. In the world of non-GC, an object is sent -dealloc when it has been released enough times not to stick around. The object should then free any memory claimed during its lifetime, and finally call [super dealloc]. Note that this means objects which use the voodoo cohesion of “OK, I’ll clean up all my resources in -dealloc” probably aren’t going to work too well if the garbage collection switch is flipped.

Behaviour of constructors and destructors under exception-handling conditions. Exceptions are a rarity in Cocoa code (we didn’t have language-level exceptions for the first decade, and then there was a feeling that they’re too expensive; C++ programmers like the Leopard 64-bit runtime because ObjC exceptions and C++ exceptions are compatible but that’s not the case in the NeXT runtime) but obviously a constructor is an atomic operation. You can either initialise an object or you can’t; there’s no half-object. Therefore if an -init… method catches, the thing to do is unwind the initialisation and return nil. The only thing I can think to say for having exceptions around destruction time is “don’t”, but maybe a commenter will have better ideas.

Importance of default constructors. All classes implement -init, except those that don’t ;-). Usually if there’s a parameterised initialiser (-initWithFoo:) then that will be the designated initialiser, and -init will just return [self initWithFoo: someReasonableDefaultValueForFoo];. If there’s no reasonable default, then there’s no -init. And sometimes you just shouldn’t use -init, for instance NSNull or NSWorkspace.

Time at which a destructor or finalizer is called. See How does reference counting work? for a discussion of when objects get dealloced. In the garbage-collected world, an object will be finalized at some time after it is no longer reachable in the object graph. When that is exactly really depends on the implementation of the collector and shouldn’t be relied on. Temporal cohesion (“B happens after A, therefore A has been done before B”) is usually bad.

Wisdom of overriding the language’s built-in operators, including assignment and equality. This is such a brain-damaged idea that the language doesn’t even let you do it.

How memory is handled as objects are created and destroyed or as they are declared and go out of scope. How does reference counting work? How do I start using the garbage collector?

posted by Graham Lee at 22:33  

Tuesday, June 10, 2008

ObjC FAQ update

Added a question about the ObjC 2.0 garbage collector. Sorry it’s been so long in coming! I’ll try and add a few more ObjC 2.0 questions over the coming days.

posted by Graham Lee at 15:24  

Powered by WordPress