Deep Dive into Objective‑C Object Memory Layout and Runtime Structures
This article explores the low‑level implementation of Objective‑C objects by examining instance memory allocation, the differences between class_getInstanceSize and malloc_size, the internal structures of instance, class, and meta‑class objects, and how isa and superclass pointers link them together.
When we create an Objective‑C object with NSObject *obj = [[NSObject alloc] init]; , the compiler eventually turns this into C/C++ code and then into assembly, which finally becomes a binary that the CPU can execute.
To see the actual code generated for obj , we can run the clang front‑end with xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main_arm64.cpp . The resulting main_arm64.cpp shows that a NSObject instance is compiled into a C++ struct that contains only an isa pointer. On a 64‑bit system this struct occupies 8 bytes, but the operating system always allocates at least 16 bytes for the object because of the alignment rules enforced by the Core Foundation framework.
Calling class_getInstanceSize([NSObject class]) returns the size of the instance fields (8 bytes), while malloc_size(obj) returns the actual memory block size (16 bytes). The discrepancy is caused by the alignedInstanceSize() function, which pads the size to the minimum of 16 bytes.
Objective‑C objects can be divided into three kinds: instance objects, class objects, and meta‑class objects. All three are represented by a Class ‑type struct (essentially typedef struct objc_class *Class; ). The class object stores the class’s ivars, properties, instance methods, and protocol list, while the meta‑class stores class methods. The instance object stores only its ivars (plus the isa pointer).
We can obtain the addresses of these objects at runtime. For example, creating two NSObject instances obj1 and obj2 and then retrieving their class objects with object_getClass(obj1) yields distinct class object pointers, but the same meta‑class pointer for both, confirming that a class has a single class object and a single meta‑class object.
The isa pointer of an instance points to its class object, but on 64‑bit iOS the pointer is tagged; the real address is obtained by masking with ISA_MASK (e.g., 0x00007ffffffffff8ULL on x86_64). After masking, the isa of obj matches the address of its class object.
The class object’s isa points to its meta‑class, and the meta‑class’s isa points to the root meta‑class (the meta‑class of NSObject ). The superclass pointer of a class object points to its superclass’s class object, forming a chain that ends at NSObject , whose superclass is nil . Meta‑classes follow the same pattern, linking to the meta‑class of the superclass.
In summary:
Objective‑C objects consist of instance, class, and meta‑class structs.
Instance objects store only ivars; class objects store ivars, properties, instance methods, and protocols; meta‑classes store class methods.
Memory allocation for an instance is padded to 16 bytes, though the logical size may be smaller.
The isa pointer links an instance to its class, a class to its meta‑class, and a meta‑class to the root meta‑class.
The superclass pointer links a class to its superclass’s class object, and similarly for meta‑classes.
Understanding these relationships helps developers debug obscure runtime issues and gives insight into how the Objective‑C runtime manages objects under the hood.
JD Tech
Official JD technology sharing platform. All the cutting‑edge JD tech, innovative insights, and open‑source solutions you’re looking for, all in one place.
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.