探究Objective-C对象的内存模型(一):实例对象
前言
在大学时期学习C时,为了深入了解C的机制及实现原理,老师推荐了本《深度探索C++对象模型》,草率读完一遍后对当时的我来说收获巨大,一度自信心膨胀…
然而在学习OC时,相关的深入的书籍有些缺乏,只能通过零零散散的博客了解个大概。
因此,本系列文章通过查阅OC的Runtime源码+动态调试的方法来梳理一下OC中对象的内存模型。
一、NSObject实例对象内存模型
为了解NSObject实例对象的内存模型,首先需要创建一个实例对象。
a - 创建NSObject实例对象
创建实例对象代码如下:
1 | NSObject *obj = [[NSObject alloc] init]; |
要想知道obj所指向的对象在内存中是怎样存储的,需要知道两个东西:
obj指针所指向对象的地址。obj指针所指向对象的大小。
b - 获取实例对象地址
地址,很容易获得:
1 | NSLog(@"obj -> %p",obj); |
c - 获取实例对象大小
当我想用以下代码获得对象的大小时,出现了问题:
1 | NSLog(@"obj size = %d",sizeof(NSObject)); |
编译报错:Application of 'sizeof' to interface 'NSObject' is not supported on this architecture and platform
在《NSObject 底层本质》博客中提供了三种思路:
- 方式一:通过
clang -rewrite-objc main.m -o main.cpp命令,把OC代码转换为C代码,在C代码中查看NSObject的底层实现。 - 方式二:通过
class_getInstanceSize([NSObject class])获取NSObject对象实例所占用的内存大小。 - 方式三:通过
malloc_size((__bridge const void *)obj)来获取系统为obj分配的内存大小。
通过上述博客可知:Runtime为obj对象分配了16字节的内存,但obj对象实际只会占用8字节,这8个字节主要用来存放isa指针相关的值。
d - obj对象的本质
同样,通过上述博客可知,NSObject对象其本质就是下面代码中的结构体:
1 | struct MY_NSObject_IMPL { |
彩蛋问题一:如何在栈内存中创建一个NSObject的对象?
那么,问题来了,我来提出一个与C++的一些黑魔法问题类似的问题:如何在栈内存中创建一个NSObject的对象呢?(答案见文末)
e - obj对象内存模型(图)
假设obj指针所指向对象的内存地址为0x100611690,那么obj对象的内存模型如下:

二、单继承
a - 创建Person类(继承自NSObject)
创建一个Person类继承于NSObject类,为了降低分析的复杂度,采用基本数据类型做为成员变量,代码如下:
1 | @interface Person : NSObject { |
b - 创建Person类的实例对象
1 | Person * p = [[Person alloc] init]; |
c - p的本质
1 | struct My_Person_IMPL { |
彩蛋问题2:如何在栈内存中创建一个Person的对象?
d - p的内存模型
假设p指针所指向对象的内存地址为0x100611690,那么p对象的内存模型如下:

e - 创建Student类(继承自Person)
1 | @interface Student : Person{ |
f - 创建Student类的实例对象
1 | Student *s = [[Student alloc] init]; |
g - s的本质
1 | struct My_Student_IMPL { |
彩蛋问题3:如何在栈内存中创建一个Student的对象?
h - s的内存模型
假设s指针所指向对象的内存地址为0x100611690,那么s对象的内存模型如下:

三、多继承
什么?
你看到了这里?
你还想了解Objective-C的多继承?
看来你的基础不够牢固呀。
大声跟我念三遍:
Objective-C不支持多继承!
Objective-C不支持多继承!
Objective-C不支持多继承!
四、菱形继承
啥?
你咋又来了?
不是已经告诉你了Objective-C不支持多继承吗?
那肯定更不会存在菱形继承了!!!
五、彩蛋问题答案
在实现My_Person_IMPL/My_Student_IMPL的时候,记得一定要设置内存对齐的参数为4,只有这样,才能正确将内存的里值取出来。
1 |
|
输出如下:
1 | 2021-07-20 21:54:23.867409+0800 testCommand[2028:56637] objOnStack = <NSObject: 0x7ffeefbff4f8> |
六、小结
本文小结如下:
- 实例对象的前8个字节存储了
isa指针,剩余的内存用来存储成员变量。 - OC对象单继承的内存模型与C++类似,在父类对象基础上(不严谨),添加自己的成员变量。
七、新问题
问题一:isa指针所指向的内存里都存储了哪些东西?
问题二:下面代码输出结果,为什么与预期不符?
1 | int main(int argc, const char * argv[]) { |