I am curious about how retain/release work internally. On the face, it seems like there's an integer related to each instance of an NSObject
, which gets increased and decreased when you call -retain
and -release
, respectively.
But taking a look at NSObject
, the only instance variable it has is the isa
variable, for determining its class type.
So where are retain counts for individual objects stored? Not that I'm going to muck around with it, but just for my own edification.
Is it stored with the NSObject
, but hidden away in some Objective C implementation detail? If so, that seems like a bad design to me. One should be able to create their own root class and handle their own retain/release counting in a similar fashion (not that it's a good idea--one would have to have a very good reason not to use NSObject
).
The storage location for the retain count depends on both the runtime in use and the class implementation.
For Apple's Objective-C runtime, you can figure out a lot by digging into the source code of the Objective-C runtime.
For example, if you're using ARC (and I think even if you're not), the reference counts for most objects are stored in hash tables. Have a look at the _objc_rootRetain
function in runtime/objc-arr.mm
. I don't know exactly why they did this. Perhaps it's a way of keeping retain counts together for better cache behavior (which is important under ARC because ARC adjusts retain counts more often than non-ARC code usually does).
However, some classes override retain
and related methods and store the retain count elsewhere. For example, when debugging a memory leak I discovered that CALayer
does this. Instead of using the runtime's normal retain count mechanism, a CALayer
stores its retain count in a private C++ implementation object. This is rather frustrating because it means the Instruments Allocations instrument doesn't log retains and releases of CALayer
objects.