Understanding the dealloc Process of Objective‑C Objects in MRC and ARC
This article explains how Objective‑C objects are deallocated in both manual reference counting (MRC) and Automatic Reference Counting (ARC), outlines common pitfalls such as using __weak in dealloc, and details the runtime flow from _objc_rootDealloc to the final memory free operation.
In the previous article we introduced the creation process of OC objects; this article explains the deallocation (dealloc) process.
In manual reference counting (MRC) you must call release; example:
-(void)dealloc
{
/* release ivars, remove observers, stop timers, remove notifications, nil delegates, etc. */
[super dealloc];
}Under ARC, most objects are handled automatically; only non‑Cocoa objects need manual handling:
-(void)dealloc
{
/* non‑OC objects such as CF objects */
}Important notes when implementing dealloc:
Do not use __weak inside dealloc ; it can cause a crash because the object is already being deallocated.
Prefer directly setting instance variables to nil rather than using properties.
Avoid calling other methods, especially GCD or thread‑related APIs, from dealloc .
The article then dives into the runtime implementation of dealloc in NSObject. The flow is:
Call _objc_rootDealloc(self) .
_objc_rootDealloc forwards to objc_object::rootDealloc() .
rootDealloc either frees the object directly or calls object_dispose(obj) depending on isa flags.
object_dispose invokes objc_destructInstance(obj) and then frees the memory.
objc_destructInstance runs C++ destructors, removes associated objects, and clears ARC ivar bookkeeping.
Key runtime functions are shown below:
Void _objc_rootDealloc(id obj)
{
assert(obj);
obj->rootDealloc();
} inline void objc_object::rootDealloc()
{
if (isTaggedPointer()) return;
if (fastpath(isa.nonpointer && !isa.weakly_referenced && !isa.has_assoc && !isa.has_cxx_dtor && !isa.has_sidetable_rc))
{
assert(!sidetable_present());
free(this);
}
else
{
object_dispose((id)this);
}
} id object_dispose(id obj)
{
if (!obj) return nil;
objc_destructInstance(obj);
free(obj);
return nil;
} void *objc_destructInstance(id obj)
{
if (obj) {
bool cxx = obj->hasCxxDtor();
bool assoc = obj->hasAssociatedObjects();
if (cxx) object_cxxDestruct(obj);
if (assoc) _object_remove_assocations(obj);
obj->clearDeallocating();
}
return obj;
}Further details of object_cxxDestruct , _object_remove_assocations , and clearDeallocating are provided, showing how C++ destructors are called, how associated objects are removed, and how weak references and side‑table reference counts are cleared.
The article concludes with a flowchart and a summary of the main steps: call C++ destructors, remove associations, clear deallocating state, and finally free the memory.
JD Retail Technology
Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.